Commit a617d062 authored by Rémy Oudompheng's avatar Rémy Oudompheng

cmd/6g, cmd/8g: simplify integer division code.

Change suggested by iant. The compiler generates
special code for a/b when a is -0x80...0 and b = -1.
A single instruction can cover the case where b is -1,
so only one comparison is needed.

Fixes #3551.

R=golang-dev, rsc
CC=golang-dev
https://golang.org/cl/6922049
parent 4766a35e
...@@ -454,10 +454,10 @@ void ...@@ -454,10 +454,10 @@ void
dodiv(int op, Node *nl, Node *nr, Node *res) dodiv(int op, Node *nl, Node *nr, Node *res)
{ {
int a, check; int a, check;
Node n3, n4, n5; Node n3, n4;
Type *t, *t0; Type *t, *t0;
Node ax, dx, ax1, n31, oldax, olddx; Node ax, dx, ax1, n31, oldax, olddx;
Prog *p1, *p2, *p3; Prog *p1, *p2;
// Have to be careful about handling // Have to be careful about handling
// most negative int divided by -1 correctly. // most negative int divided by -1 correctly.
...@@ -508,30 +508,22 @@ dodiv(int op, Node *nl, Node *nr, Node *res) ...@@ -508,30 +508,22 @@ dodiv(int op, Node *nl, Node *nr, Node *res)
gmove(&n31, &n3); gmove(&n31, &n3);
} }
p3 = P; p2 = P;
if(check) { if(check) {
nodconst(&n4, t, -1); nodconst(&n4, t, -1);
gins(optoas(OCMP, t), &n3, &n4); gins(optoas(OCMP, t), &n3, &n4);
p1 = gbranch(optoas(ONE, t), T, +1); p1 = gbranch(optoas(ONE, t), T, +1);
nodconst(&n4, t, -1LL<<(t->width*8-1)); if(op == ODIV) {
if(t->width == 8) { // a / (-1) is -a.
n5 = n4; gins(optoas(OMINUS, t), N, &ax);
regalloc(&n4, t, N); gmove(&ax, res);
gins(AMOVQ, &n5, &n4); } else {
} // a % (-1) is 0.
gins(optoas(OCMP, t), &ax, &n4);
p2 = gbranch(optoas(ONE, t), T, +1);
if(op == ODIV)
gmove(&n4, res);
if(t->width == 8)
regfree(&n4);
if(op == OMOD) {
nodconst(&n4, t, 0); nodconst(&n4, t, 0);
gmove(&n4, res); gmove(&n4, res);
} }
p3 = gbranch(AJMP, T, 0); p2 = gbranch(AJMP, T, 0);
patch(p1, pc); patch(p1, pc);
patch(p2, pc);
} }
savex(D_DX, &dx, &olddx, res, t); savex(D_DX, &dx, &olddx, res, t);
if(!issigned[t->etype]) { if(!issigned[t->etype]) {
...@@ -547,7 +539,7 @@ dodiv(int op, Node *nl, Node *nr, Node *res) ...@@ -547,7 +539,7 @@ dodiv(int op, Node *nl, Node *nr, Node *res)
gmove(&dx, res); gmove(&dx, res);
restx(&dx, &olddx); restx(&dx, &olddx);
if(check) if(check)
patch(p3, pc); patch(p2, pc);
restx(&ax, &oldax); restx(&ax, &oldax);
} }
......
...@@ -495,7 +495,7 @@ dodiv(int op, Node *nl, Node *nr, Node *res, Node *ax, Node *dx) ...@@ -495,7 +495,7 @@ dodiv(int op, Node *nl, Node *nr, Node *res, Node *ax, Node *dx)
int check; int check;
Node n1, t1, t2, t3, t4, n4, nz; Node n1, t1, t2, t3, t4, n4, nz;
Type *t, *t0; Type *t, *t0;
Prog *p1, *p2, *p3; Prog *p1, *p2;
// Have to be careful about handling // Have to be careful about handling
// most negative int divided by -1 correctly. // most negative int divided by -1 correctly.
...@@ -544,23 +544,22 @@ dodiv(int op, Node *nl, Node *nr, Node *res, Node *ax, Node *dx) ...@@ -544,23 +544,22 @@ dodiv(int op, Node *nl, Node *nr, Node *res, Node *ax, Node *dx)
regalloc(&n1, t, N); regalloc(&n1, t, N);
gmove(&t2, &n1); gmove(&t2, &n1);
gmove(&t1, ax); gmove(&t1, ax);
p3 = P; p2 = P;
if(check) { if(check) {
nodconst(&n4, t, -1); nodconst(&n4, t, -1);
gins(optoas(OCMP, t), &n1, &n4); gins(optoas(OCMP, t), &n1, &n4);
p1 = gbranch(optoas(ONE, t), T, +1); p1 = gbranch(optoas(ONE, t), T, +1);
nodconst(&n4, t, -1LL<<(t->width*8-1)); if(op == ODIV) {
gins(optoas(OCMP, t), ax, &n4); // a / (-1) is -a.
p2 = gbranch(optoas(ONE, t), T, +1); gins(optoas(OMINUS, t), N, ax);
if(op == ODIV) gmove(ax, res);
gmove(&n4, res); } else {
if(op == OMOD) { // a % (-1) is 0.
nodconst(&n4, t, 0); nodconst(&n4, t, 0);
gmove(&n4, res); gmove(&n4, res);
} }
p3 = gbranch(AJMP, T, 0); p2 = gbranch(AJMP, T, 0);
patch(p1, pc); patch(p1, pc);
patch(p2, pc);
} }
if(!issigned[t->etype]) { if(!issigned[t->etype]) {
nodconst(&nz, t, 0); nodconst(&nz, t, 0);
...@@ -575,7 +574,7 @@ dodiv(int op, Node *nl, Node *nr, Node *res, Node *ax, Node *dx) ...@@ -575,7 +574,7 @@ dodiv(int op, Node *nl, Node *nr, Node *res, Node *ax, Node *dx)
else else
gmove(dx, res); gmove(dx, res);
if(check) if(check)
patch(p3, pc); patch(p2, pc);
} }
static void static void
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment