1
0
mirror of https://github.com/golang/go synced 2024-11-22 06:14:39 -07:00

divide by a constant power of 2

R=rsc
OCL=32858
CL=32858
This commit is contained in:
Ken Thompson 2009-08-06 22:33:12 -07:00
parent 2f9c48f6d1
commit f1baf78247
4 changed files with 181 additions and 2 deletions

View File

@ -125,6 +125,8 @@ void sudoclean(void);
int sudoaddable(int, Node*, Addr*); int sudoaddable(int, Node*, Addr*);
void afunclit(Addr*); void afunclit(Addr*);
void datagostring(Strlit*, Addr*); void datagostring(Strlit*, Addr*);
int powtwo(Node*);
Type* tounsigned(Type*);
/* /*
* obj.c * obj.c

View File

@ -533,8 +533,8 @@ dodiv(int op, Node *nl, Node *nr, Node *res, Node *ax, Node *dx)
void void
cgen_div(int op, Node *nl, Node *nr, Node *res) cgen_div(int op, Node *nl, Node *nr, Node *res)
{ {
Node ax, dx, oldax, olddx, n1, n2; Node ax, dx, oldax, olddx, n1, n2, n3;
int rax, rdx; int rax, rdx, n, w;
if(nl->ullman >= UINF) { if(nl->ullman >= UINF) {
tempname(&n1, nl->type); tempname(&n1, nl->type);
@ -547,6 +547,86 @@ cgen_div(int op, Node *nl, Node *nr, Node *res)
nr = &n2; nr = &n2;
} }
if(nr->op != OLITERAL)
goto longdiv;
// special cases of mod/div
// by a constant
n = powtwo(nr);
w = nl->type->width*8;
if(n+1 >= w) {
// just sign bit
goto longdiv;
}
if(n < 0)
goto divbymul;
if(op == OMOD) {
// todo
goto longdiv;
}
switch(n) {
case 0:
// divide by 1
cgen(nl, res);
return;
case 1:
// divide by 2
regalloc(&n1, nl->type, res);
cgen(nl, &n1);
if(issigned[nl->type->etype]) {
// develop -1 iff nl is negative
regalloc(&n2, nl->type, N);
gmove(&n1, &n2);
nodconst(&n3, nl->type, w-1);
gins(optoas(ORSH, nl->type), &n3, &n2);
gins(optoas(OSUB, nl->type), &n2, &n1);
regfree(&n2);
}
nodconst(&n2, nl->type, n);
gins(optoas(ORSH, nl->type), &n2, &n1);
gmove(&n1, res);
regfree(&n1);
return;
default:
regalloc(&n1, nl->type, res);
cgen(nl, &n1);
if(issigned[nl->type->etype]) {
// develop (2^k)-1 iff nl is negative
regalloc(&n2, nl->type, N);
gmove(&n1, &n2);
nodconst(&n3, nl->type, w-1);
gins(optoas(ORSH, nl->type), &n3, &n2);
nodconst(&n3, nl->type, w-n);
gins(optoas(ORSH, tounsigned(nl->type)), &n3, &n2);
gins(optoas(OADD, nl->type), &n2, &n1);
regfree(&n2);
}
nodconst(&n2, nl->type, n);
gins(optoas(ORSH, nl->type), &n2, &n1);
gmove(&n1, res);
regfree(&n1);
}
return;
divbymul:
switch(simtype[nl->type->etype]) {
default:
goto longdiv;
case TINT32:
case TUINT32:
case TINT64:
case TUINT64:
break;
}
// todo
goto longdiv;
longdiv:
rax = reg[D_AX]; rax = reg[D_AX];
rdx = reg[D_DX]; rdx = reg[D_DX];

View File

@ -1861,3 +1861,55 @@ no:
sudoclean(); sudoclean();
return 0; return 0;
} }
int
powtwo(Node *n)
{
uvlong v, b;
int i;
if(n == N || n->op != OLITERAL || n->type == T)
goto no;
if(!isint[n->type->etype])
goto no;
v = mpgetfix(n->val.u.xval);
b = 1ULL;
for(i=0; i<64; i++) {
if(b == v)
return i;
b = b<<1;
}
no:
return -1;
}
Type*
tounsigned(Type *t)
{
// this is types[et+1], but not sure
// that this relation is immutable
switch(t->etype) {
default:
print("tounsigned: unknown type %T\n", t);
break;
case TINT:
t = types[TUINT];
break;
case TINT8:
t = types[TUINT8];
break;
case TINT16:
t = types[TUINT16];
break;
case TINT32:
t = types[TUINT32];
break;
case TINT64:
t = types[TUINT64];
break;
}
return t;
}

45
test/ken/divconst.go Normal file
View File

@ -0,0 +1,45 @@
// $G $D/$F.go && $L $F.$A && ./$A.out
// Copyright 2009 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
import "rand"
func test(a,b,c int64);
func
main()
{
var a, b int64;
for i:=0; i<1e6; i++ {
a := rand.Int63() - 1<<62;
b = a/1; test(a,b,1);
b = a/2; test(a,b,2);
b = a/3; test(a,b,3);
b = a/4; test(a,b,4);
b = a/5; test(a,b,5);
b = a/6; test(a,b,6);
b = a/7; test(a,b,7);
b = a/8; test(a,b,8);
b = a/16; test(a,b,16);
b = a/32; test(a,b,32);
b = a/64; test(a,b,64);
b = a/128; test(a,b,128);
b = a/256; test(a,b,256);
b = a/16384; test(a,b,16384);
}
}
func
test(a,b,c int64)
{
d := a/c;
if d != b {
panicln(a, b, c, d);
}
}