--- old/src/share/vm/opto/divnode.cpp 2009-02-04 18:04:45.053345241 +0100 +++ new/src/share/vm/opto/divnode.cpp 2009-02-04 18:04:44.937866196 +0100 @@ -1,5 +1,5 @@ /* - * Copyright 1997-2008 Sun Microsystems, Inc. All Rights Reserved. + * Copyright 1997-2009 Sun Microsystems, Inc. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -244,42 +244,73 @@ //---------------------long_by_long_mulhi-------------------------------------- // Generate ideal node graph for upper half of a 64 bit x 64 bit multiplication -static Node *long_by_long_mulhi( PhaseGVN *phase, Node *dividend, jlong magic_const) { +static Node* long_by_long_mulhi(PhaseGVN* phase, Node* dividend, jlong magic_const) { // If the architecture supports a 64x64 mulhi, there is // no need to synthesize it in ideal nodes. if (Matcher::has_match_rule(Op_MulHiL)) { - Node *v = phase->longcon(magic_const); + Node* v = phase->longcon(magic_const); return new (phase->C, 3) MulHiLNode(dividend, v); } - const int N = 64; - - Node *u_hi = phase->transform(new (phase->C, 3) RShiftLNode(dividend, phase->intcon(N / 2))); - Node *u_lo = phase->transform(new (phase->C, 3) AndLNode(dividend, phase->longcon(0xFFFFFFFF))); + // Taken from Hacker's Delight, Fig. 8-2. Multiply high signed. + // (http://www.hackersdelight.org/HDcode/mulhs.c) + // + // int mulhs(int u, int v) { + // unsigned u0, v0, w0; + // int u1, v1, w1, w2, t; + // + // u0 = u & 0xFFFF; u1 = u >> 16; + // v0 = v & 0xFFFF; v1 = v >> 16; + // w0 = u0*v0; + // t = u1*v0 + (w0 >> 16); + // w1 = t & 0xFFFF; + // w2 = t >> 16; + // w1 = u0*v1 + w1; + // return u1*v1 + w2 + (w1 >> 16); + // } + // + // Note: The version above is for 32x32 multiplications, while the + // following inline comments are adapted to 64x64. - Node *v_hi = phase->longcon(magic_const >> N/2); - Node *v_lo = phase->longcon(magic_const & 0XFFFFFFFF); + const int N = 64; - Node *hihi_product = phase->transform(new (phase->C, 3) MulLNode(u_hi, v_hi)); - Node *hilo_product = phase->transform(new (phase->C, 3) MulLNode(u_hi, v_lo)); - Node *lohi_product = phase->transform(new (phase->C, 3) MulLNode(u_lo, v_hi)); - Node *lolo_product = phase->transform(new (phase->C, 3) MulLNode(u_lo, v_lo)); - - Node *t1 = phase->transform(new (phase->C, 3) URShiftLNode(lolo_product, phase->intcon(N / 2))); - Node *t2 = phase->transform(new (phase->C, 3) AddLNode(hilo_product, t1)); - - // Construct both t3 and t4 before transforming so t2 doesn't go dead - // prematurely. - Node *t3 = new (phase->C, 3) RShiftLNode(t2, phase->intcon(N / 2)); - Node *t4 = new (phase->C, 3) AndLNode(t2, phase->longcon(0xFFFFFFFF)); - t3 = phase->transform(t3); - t4 = phase->transform(t4); - - Node *t5 = phase->transform(new (phase->C, 3) AddLNode(t4, lohi_product)); - Node *t6 = phase->transform(new (phase->C, 3) RShiftLNode(t5, phase->intcon(N / 2))); - Node *t7 = phase->transform(new (phase->C, 3) AddLNode(t3, hihi_product)); + // u0 = u & 0xFFFFFFFF; u1 = u >> 32; + Node* u0 = phase->transform(new (phase->C, 3) AndLNode(dividend, phase->longcon(0xFFFFFFFF))); + Node* u1 = phase->transform(new (phase->C, 3) RShiftLNode(dividend, phase->intcon(N / 2))); + + // v0 = v & 0xFFFFFFFF; v1 = v >> 32; + Node* v0 = phase->longcon(magic_const & 0xFFFFFFFF); + Node* v1 = phase->longcon(magic_const >> (N / 2)); + + // w0 = u0*v0; + Node* w0 = phase->transform(new (phase->C, 3) MulLNode(u0, v0)); + + // t = u1*v0 + (w0 >> 32); + Node* u1v0 = phase->transform(new (phase->C, 3) MulLNode(u1, v0)); + Node* temp = phase->transform(new (phase->C, 3) URShiftLNode(w0, phase->intcon(N / 2))); + Node* t = phase->transform(new (phase->C, 3) AddLNode(u1v0, temp)); + + // w1 = t & 0xFFFFFFFF; + Node* w1 = new (phase->C, 3) AndLNode(t, phase->longcon(0xFFFFFFFF)); + + // w2 = t >> 32; + Node* w2 = new (phase->C, 3) RShiftLNode(t, phase->intcon(N / 2)); + + // 6732154: Construct both w1 and w2 before transforming, so t + // doesn't go dead prematurely. + w1 = phase->transform(w1); + w2 = phase->transform(w2); + + // w1 = u0*v1 + w1; + Node* u0v1 = phase->transform(new (phase->C, 3) MulLNode(u0, v1)); + w1 = phase->transform(new (phase->C, 3) AddLNode(u0v1, w1)); + + // return u1*v1 + w2 + (w1 >> 32); + Node* u1v1 = phase->transform(new (phase->C, 3) MulLNode(u1, v1)); + Node* temp1 = phase->transform(new (phase->C, 3) AddLNode(u1v1, w2)); + Node* temp2 = phase->transform(new (phase->C, 3) RShiftLNode(w1, phase->intcon(N / 2))); - return new (phase->C, 3) AddLNode(t7, t6); + return new (phase->C, 3) AddLNode(temp1, temp2); } --- /dev/null 2009-02-04 18:04:45.000000000 +0100 +++ new/test/compiler/6800154/Test6800154.java 2009-02-04 18:04:45.561746755 +0100 @@ -0,0 +1,108 @@ +/* + * Copyright 2009 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +/** + * @test + * @bug 6800154 + * @summary Add comments to long_by_long_mulhi() for better understandability + * + * @run main/othervm -Xcomp -XX:CompileOnly=Test6800154.divcomp Test6800154 + */ + +public class Test6800154 { + public static void main(String[] args) + { + div(0); + div(1); + div(1423487); + div(4444441); + div(4918923241323L); + div(-1); + div(-24351); + div(0x3333); + div(0x0000000080000000L); + div(0x7fffffffffffffffL); + div(0x8000000000000000L); + } + + static final int N = 11; + + static final long DIV1 = 2; + static final long DIV2 = 17; + static final long DIV3 = 24123; + static final long DIV4 = -4423423234231423L; + static final long DIV5 = -1; + static final long DIV6 = 123444442344L; + static final long DIV7 = 1; + static final long DIV8 = 0x7fffffffffffffffL; + static final long DIV9 = 143444; + static final long DIV10 = 12342; + static final long DIV11 = 0x0000000080000000L; + + static void div(long a) + { + // Element at 0 is left empty intentionally. + long[] expected = new long[N + 1]; + long[] result = new long[N + 1]; + + divint(expected, a); + divcomp(result, a); + + for (int i = 1; i <= N; i++) { + if (result[i] != expected[i]) + throw new InternalError("Division of " + a + " failed at " + i + ": " + result + " != " + expected); + } + } + + static void divint(long[] la, long a) + { + // Element at 0 is left empty intentionally. + la[1] = a / DIV1; + la[2] = a / DIV2; + la[3] = a / DIV3; + la[4] = a / DIV4; + la[5] = a / DIV5; + la[6] = a / DIV6; + la[7] = a / DIV7; + la[8] = a / DIV8; + la[9] = a / DIV9; + la[10] = a / DIV10; + la[11] = a / DIV11; + } + + static void divcomp(long[] la, long a) + { + // Element at 0 is left empty intentionally. + la[1] = a / DIV1; + la[2] = a / DIV2; + la[3] = a / DIV3; + la[4] = a / DIV4; + la[5] = a / DIV5; + la[6] = a / DIV6; + la[7] = a / DIV7; + la[8] = a / DIV8; + la[9] = a / DIV9; + la[10] = a / DIV10; + la[11] = a / DIV11; + } +}