divide by a constant power of 2
R=rsc
OCL=32858
CL=32858
diff --git a/src/cmd/6g/gg.h b/src/cmd/6g/gg.h
index ce5f6c8..f9f50cc 100644
--- a/src/cmd/6g/gg.h
+++ b/src/cmd/6g/gg.h
@@ -125,6 +125,8 @@
int sudoaddable(int, Node*, Addr*);
void afunclit(Addr*);
void datagostring(Strlit*, Addr*);
+int powtwo(Node*);
+Type* tounsigned(Type*);
/*
* obj.c
diff --git a/src/cmd/6g/ggen.c b/src/cmd/6g/ggen.c
index 64220bc..4e71f75 100644
--- a/src/cmd/6g/ggen.c
+++ b/src/cmd/6g/ggen.c
@@ -533,8 +533,8 @@
void
cgen_div(int op, Node *nl, Node *nr, Node *res)
{
- Node ax, dx, oldax, olddx, n1, n2;
- int rax, rdx;
+ Node ax, dx, oldax, olddx, n1, n2, n3;
+ int rax, rdx, n, w;
if(nl->ullman >= UINF) {
tempname(&n1, nl->type);
@@ -547,6 +547,86 @@
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];
rdx = reg[D_DX];
diff --git a/src/cmd/6g/gsubr.c b/src/cmd/6g/gsubr.c
index 5ed0a81..136a8d5 100644
--- a/src/cmd/6g/gsubr.c
+++ b/src/cmd/6g/gsubr.c
@@ -1861,3 +1861,55 @@
sudoclean();
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;
+}
diff --git a/test/ken/divconst.go b/test/ken/divconst.go
new file mode 100644
index 0000000..9042b1e
--- /dev/null
+++ b/test/ken/divconst.go
@@ -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);
+ }
+}