6800154: Add comments to long_by_long_mulhi() for better understandability

Fri, 13 Feb 2009 09:09:35 -0800

author
twisti
date
Fri, 13 Feb 2009 09:09:35 -0800
changeset 1002
bbef4344adb2
parent 1001
91263420e1c6
child 1003
30663ca5e8f4

6800154: Add comments to long_by_long_mulhi() for better understandability
Summary: This patch adds a comment pointing to the Hacker's Delight version of the algorithm plus a verbatim copy of it. Furthermore it adds inline comments.
Reviewed-by: kvn, jrose

src/share/vm/opto/divnode.cpp file | annotate | diff | comparison | revisions
test/compiler/6603011/Test.java file | annotate | diff | comparison | revisions
test/compiler/6800154/Test6800154.java file | annotate | diff | comparison | revisions
     1.1 --- a/src/share/vm/opto/divnode.cpp	Fri Feb 06 13:31:03 2009 -0800
     1.2 +++ b/src/share/vm/opto/divnode.cpp	Fri Feb 13 09:09:35 2009 -0800
     1.3 @@ -1,5 +1,5 @@
     1.4  /*
     1.5 - * Copyright 1997-2008 Sun Microsystems, Inc.  All Rights Reserved.
     1.6 + * Copyright 1997-2009 Sun Microsystems, Inc.  All Rights Reserved.
     1.7   * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
     1.8   *
     1.9   * This code is free software; you can redistribute it and/or modify it
    1.10 @@ -244,42 +244,73 @@
    1.11  
    1.12  //---------------------long_by_long_mulhi--------------------------------------
    1.13  // Generate ideal node graph for upper half of a 64 bit x 64 bit multiplication
    1.14 -static Node *long_by_long_mulhi( PhaseGVN *phase, Node *dividend, jlong magic_const) {
    1.15 +static Node* long_by_long_mulhi(PhaseGVN* phase, Node* dividend, jlong magic_const) {
    1.16    // If the architecture supports a 64x64 mulhi, there is
    1.17    // no need to synthesize it in ideal nodes.
    1.18    if (Matcher::has_match_rule(Op_MulHiL)) {
    1.19 -    Node *v = phase->longcon(magic_const);
    1.20 +    Node* v = phase->longcon(magic_const);
    1.21      return new (phase->C, 3) MulHiLNode(dividend, v);
    1.22    }
    1.23  
    1.24 +  // Taken from Hacker's Delight, Fig. 8-2. Multiply high signed.
    1.25 +  // (http://www.hackersdelight.org/HDcode/mulhs.c)
    1.26 +  //
    1.27 +  // int mulhs(int u, int v) {
    1.28 +  //    unsigned u0, v0, w0;
    1.29 +  //    int u1, v1, w1, w2, t;
    1.30 +  //
    1.31 +  //    u0 = u & 0xFFFF;  u1 = u >> 16;
    1.32 +  //    v0 = v & 0xFFFF;  v1 = v >> 16;
    1.33 +  //    w0 = u0*v0;
    1.34 +  //    t  = u1*v0 + (w0 >> 16);
    1.35 +  //    w1 = t & 0xFFFF;
    1.36 +  //    w2 = t >> 16;
    1.37 +  //    w1 = u0*v1 + w1;
    1.38 +  //    return u1*v1 + w2 + (w1 >> 16);
    1.39 +  // }
    1.40 +  //
    1.41 +  // Note: The version above is for 32x32 multiplications, while the
    1.42 +  // following inline comments are adapted to 64x64.
    1.43 +
    1.44    const int N = 64;
    1.45  
    1.46 -  Node *u_hi = phase->transform(new (phase->C, 3) RShiftLNode(dividend, phase->intcon(N / 2)));
    1.47 -  Node *u_lo = phase->transform(new (phase->C, 3) AndLNode(dividend, phase->longcon(0xFFFFFFFF)));
    1.48 +  // u0 = u & 0xFFFFFFFF;  u1 = u >> 32;
    1.49 +  Node* u0 = phase->transform(new (phase->C, 3) AndLNode(dividend, phase->longcon(0xFFFFFFFF)));
    1.50 +  Node* u1 = phase->transform(new (phase->C, 3) RShiftLNode(dividend, phase->intcon(N / 2)));
    1.51  
    1.52 -  Node *v_hi = phase->longcon(magic_const >> N/2);
    1.53 -  Node *v_lo = phase->longcon(magic_const & 0XFFFFFFFF);
    1.54 +  // v0 = v & 0xFFFFFFFF;  v1 = v >> 32;
    1.55 +  Node* v0 = phase->longcon(magic_const & 0xFFFFFFFF);
    1.56 +  Node* v1 = phase->longcon(magic_const >> (N / 2));
    1.57  
    1.58 -  Node *hihi_product = phase->transform(new (phase->C, 3) MulLNode(u_hi, v_hi));
    1.59 -  Node *hilo_product = phase->transform(new (phase->C, 3) MulLNode(u_hi, v_lo));
    1.60 -  Node *lohi_product = phase->transform(new (phase->C, 3) MulLNode(u_lo, v_hi));
    1.61 -  Node *lolo_product = phase->transform(new (phase->C, 3) MulLNode(u_lo, v_lo));
    1.62 +  // w0 = u0*v0;
    1.63 +  Node* w0 = phase->transform(new (phase->C, 3) MulLNode(u0, v0));
    1.64  
    1.65 -  Node *t1 = phase->transform(new (phase->C, 3) URShiftLNode(lolo_product, phase->intcon(N / 2)));
    1.66 -  Node *t2 = phase->transform(new (phase->C, 3) AddLNode(hilo_product, t1));
    1.67 +  // t = u1*v0 + (w0 >> 32);
    1.68 +  Node* u1v0 = phase->transform(new (phase->C, 3) MulLNode(u1, v0));
    1.69 +  Node* temp = phase->transform(new (phase->C, 3) URShiftLNode(w0, phase->intcon(N / 2)));
    1.70 +  Node* t    = phase->transform(new (phase->C, 3) AddLNode(u1v0, temp));
    1.71  
    1.72 -  // Construct both t3 and t4 before transforming so t2 doesn't go dead
    1.73 -  // prematurely.
    1.74 -  Node *t3 = new (phase->C, 3) RShiftLNode(t2, phase->intcon(N / 2));
    1.75 -  Node *t4 = new (phase->C, 3) AndLNode(t2, phase->longcon(0xFFFFFFFF));
    1.76 -  t3 = phase->transform(t3);
    1.77 -  t4 = phase->transform(t4);
    1.78 +  // w1 = t & 0xFFFFFFFF;
    1.79 +  Node* w1 = new (phase->C, 3) AndLNode(t, phase->longcon(0xFFFFFFFF));
    1.80  
    1.81 -  Node *t5 = phase->transform(new (phase->C, 3) AddLNode(t4, lohi_product));
    1.82 -  Node *t6 = phase->transform(new (phase->C, 3) RShiftLNode(t5, phase->intcon(N / 2)));
    1.83 -  Node *t7 = phase->transform(new (phase->C, 3) AddLNode(t3, hihi_product));
    1.84 +  // w2 = t >> 32;
    1.85 +  Node* w2 = new (phase->C, 3) RShiftLNode(t, phase->intcon(N / 2));
    1.86  
    1.87 -  return new (phase->C, 3) AddLNode(t7, t6);
    1.88 +  // 6732154: Construct both w1 and w2 before transforming, so t
    1.89 +  // doesn't go dead prematurely.
    1.90 +  w1 = phase->transform(w1);
    1.91 +  w2 = phase->transform(w2);
    1.92 +
    1.93 +  // w1 = u0*v1 + w1;
    1.94 +  Node* u0v1 = phase->transform(new (phase->C, 3) MulLNode(u0, v1));
    1.95 +  w1         = phase->transform(new (phase->C, 3) AddLNode(u0v1, w1));
    1.96 +
    1.97 +  // return u1*v1 + w2 + (w1 >> 32);
    1.98 +  Node* u1v1  = phase->transform(new (phase->C, 3) MulLNode(u1, v1));
    1.99 +  Node* temp1 = phase->transform(new (phase->C, 3) AddLNode(u1v1, w2));
   1.100 +  Node* temp2 = phase->transform(new (phase->C, 3) RShiftLNode(w1, phase->intcon(N / 2)));
   1.101 +
   1.102 +  return new (phase->C, 3) AddLNode(temp1, temp2);
   1.103  }
   1.104  
   1.105  
     2.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     2.2 +++ b/test/compiler/6603011/Test.java	Fri Feb 13 09:09:35 2009 -0800
     2.3 @@ -0,0 +1,220 @@
     2.4 +/*
     2.5 + * Copyright 2009 Sun Microsystems, Inc.  All Rights Reserved.
     2.6 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
     2.7 + *
     2.8 + * This code is free software; you can redistribute it and/or modify it
     2.9 + * under the terms of the GNU General Public License version 2 only, as
    2.10 + * published by the Free Software Foundation.
    2.11 + *
    2.12 + * This code is distributed in the hope that it will be useful, but WITHOUT
    2.13 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
    2.14 + * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
    2.15 + * version 2 for more details (a copy is included in the LICENSE file that
    2.16 + * accompanied this code).
    2.17 + *
    2.18 + * You should have received a copy of the GNU General Public License version
    2.19 + * 2 along with this work; if not, write to the Free Software Foundation,
    2.20 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
    2.21 + *
    2.22 + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
    2.23 + * CA 95054 USA or visit www.sun.com if you need additional information or
    2.24 + * have any questions.
    2.25 + */
    2.26 +
    2.27 +/**
    2.28 + * @test
    2.29 + * @bug 6603011
    2.30 + * @summary long/int division by constant
    2.31 + *
    2.32 + * @run main/othervm -Xcomp -Xbatch -XX:-Inline Test
    2.33 + */
    2.34 +
    2.35 +//
    2.36 +// -XX:-Inline is essential to this test so that verification functions
    2.37 +//   divi, modi, divl and modl generate "plain" divides.
    2.38 +// -Xcomp -Xbatch are also useful to ensure the full range of
    2.39 +//   dividend and divisor combinations are tested
    2.40 +//
    2.41 +
    2.42 +import java.net.*;
    2.43 +
    2.44 +class s {
    2.45 +  static int  divi(int  dividend, int  divisor) { return dividend / divisor; }
    2.46 +  static int  modi(int  dividend, int  divisor) { return dividend % divisor; }
    2.47 +  static long divl(long dividend, long divisor) { return dividend / divisor; }
    2.48 +  static long modl(long dividend, long divisor) { return dividend % divisor; }
    2.49 +}
    2.50 +
    2.51 +public class Test implements Runnable {
    2.52 +  // Report verbose messages on failure; turn off to suppress
    2.53 +  // too much output with gross numbers of failures.
    2.54 +  static final boolean VERBOSE = true;
    2.55 +
    2.56 +  // Initailize DIVISOR so that it is final in this class.
    2.57 +  static final int DIVISOR;
    2.58 +  static {
    2.59 +    int value = 0;
    2.60 +    try {
    2.61 +      value = Integer.decode(System.getProperty("divisor"));
    2.62 +    } catch (Throwable e) {
    2.63 +    }
    2.64 +    DIVISOR = value;
    2.65 +  }
    2.66 +
    2.67 +  // The methods of interest. We want the JIT to compile these
    2.68 +  // and convert the divide into a multiply.
    2.69 +  public int divbyI (int dividend)   { return dividend / DIVISOR; }
    2.70 +  public int modbyI (int dividend)   { return dividend % DIVISOR; }
    2.71 +  public long divbyL (long dividend) { return dividend / DIVISOR; }
    2.72 +  public long modbyL (long dividend) { return dividend % DIVISOR; }
    2.73 +
    2.74 +  public int divisor() { return DIVISOR; }
    2.75 +
    2.76 +  public boolean checkI (int dividend) {
    2.77 +    int quo = divbyI(dividend);
    2.78 +    int rem = modbyI(dividend);
    2.79 +    int quo0 = s.divi(dividend, divisor());
    2.80 +    int rem0 = s.modi(dividend, divisor());
    2.81 +
    2.82 +    if (quo != quo0 || rem != rem0) {
    2.83 +      if (VERBOSE) {
    2.84 +        System.out.println("Computed: " + dividend + " / " + divisor() + " = " +
    2.85 +                           quo  + ", " + dividend + " % " + divisor() + " = " + rem );
    2.86 +        System.out.println("expected: " + dividend + " / " + divisor() + " = " +
    2.87 +                           quo0 + ", " + dividend + " % " + divisor() + " = " + rem0);
    2.88 +        // Report sign of rem failure
    2.89 +        if (rem != 0 && (rem ^ dividend) < 0) {
    2.90 +          System.out.println("  rem & dividend have different signs");
    2.91 +        }
    2.92 +        // Report range of rem failure
    2.93 +        if (java.lang.Math.abs(rem) >= java.lang.Math.abs(divisor())) {
    2.94 +          System.out.println("  remainder out of range");
    2.95 +        }
    2.96 +        // Report quo/rem identity relationship failure
    2.97 +        if ((quo * divisor()) + rem != dividend) {
    2.98 +          System.out.println("  quotien/remainder invariant broken");
    2.99 +        }
   2.100 +      }
   2.101 +      return false;
   2.102 +    }
   2.103 +    return true;
   2.104 +  }
   2.105 +
   2.106 +  public boolean checkL (long dividend) {
   2.107 +    long quo = divbyL(dividend);
   2.108 +    long rem = modbyL(dividend);
   2.109 +    long quo0 = s.divl(dividend, divisor());
   2.110 +    long rem0 = s.modl(dividend, divisor());
   2.111 +
   2.112 +    if (quo != quo0 || rem != rem0) {
   2.113 +      if (VERBOSE) {
   2.114 +        System.out.println("  " + dividend + " / " + divisor() + " = " +
   2.115 +                           quo + ", " + dividend + " % " + divisor() + " = " + rem);
   2.116 +        // Report sign of rem failure
   2.117 +        if (rem != 0 && (rem ^ dividend) < 0) {
   2.118 +          System.out.println("  rem & dividend have different signs");
   2.119 +        }
   2.120 +        // Report range of rem failure
   2.121 +        if (java.lang.Math.abs(rem) >= java.lang.Math.abs(divisor())) {
   2.122 +          System.out.println("  remainder out of range");
   2.123 +        }
   2.124 +        // Report quo/rem identity relationship failure
   2.125 +        if ((quo * divisor()) + rem != dividend) {
   2.126 +          System.out.println(" (" + quo + " * " + divisor() + ") + " + rem + " != "
   2.127 +                             + dividend);
   2.128 +        }
   2.129 +      }
   2.130 +      return false;
   2.131 +    }
   2.132 +    return true;
   2.133 +  }
   2.134 +
   2.135 +  public void run() {
   2.136 +    // Don't try to divide by zero
   2.137 +    if (divisor() == 0) return;
   2.138 +
   2.139 +    // Range of dividends to check. Try dividends from start to end
   2.140 +    // inclusive, as well as variations on those values as shifted
   2.141 +    // left.
   2.142 +    int start = -1024;
   2.143 +    int end = 1024;
   2.144 +
   2.145 +    // Test int division using a variety of dividends.
   2.146 +    int wrong = 0;
   2.147 +    int total = 0;
   2.148 +
   2.149 +    outerloop:
   2.150 +    for (int i = start; i <= end; i++) {
   2.151 +      for (int s = 0; s < 32; s += 4) {
   2.152 +        total++;
   2.153 +        int dividend = i << s;
   2.154 +        if (!checkI(dividend)) {
   2.155 +          wrong++;
   2.156 +          // Stop on the first failure
   2.157 +          // break outerloop;
   2.158 +        }
   2.159 +      }
   2.160 +    }
   2.161 +    if (wrong > 0) {
   2.162 +      System.out.println("divisor " + divisor() + ": " +
   2.163 +                         wrong + "/" + total + " wrong int divisions");
   2.164 +    }
   2.165 +
   2.166 +    // Test long division using a variety of dividends.
   2.167 +    wrong = 0;
   2.168 +    total = 0;
   2.169 +
   2.170 +    outerloop:
   2.171 +    for (int i = start; i <= end; i++) {
   2.172 +      for (int s = 0; s < 64; s += 4) {
   2.173 +        total++;
   2.174 +        long dividend = i << s;
   2.175 +        if (!checkL(dividend)) {
   2.176 +          wrong++;
   2.177 +          // Stop on the first failure
   2.178 +          // break outerloop;
   2.179 +        }
   2.180 +      }
   2.181 +    }
   2.182 +    if (wrong > 0) {
   2.183 +      System.out.println("divisor " + divisor() + ": " +
   2.184 +                         wrong + "/" + total + " wrong long divisions");
   2.185 +    }
   2.186 +
   2.187 +  }
   2.188 +
   2.189 +  // Reload this class with the "divisor" property set to the input parameter.
   2.190 +  // This allows the JIT to see q.DIVISOR as a final constant, and change
   2.191 +  // any divisions or mod operations into multiplies.
   2.192 +  public static void test_divisor(int divisor,
   2.193 +                                  URLClassLoader apploader) throws Exception {
   2.194 +    System.setProperty("divisor", "" + divisor);
   2.195 +    ClassLoader loader = new URLClassLoader(apploader.getURLs(),
   2.196 +                                            apploader.getParent());
   2.197 +    Class c = loader.loadClass("Test");
   2.198 +    Runnable r = (Runnable)c.newInstance();
   2.199 +    r.run();
   2.200 +  }
   2.201 +
   2.202 +  public static void main(String[] args) throws Exception {
   2.203 +    Class cl = Class.forName("Test");
   2.204 +    URLClassLoader apploader = (URLClassLoader)cl.getClassLoader();
   2.205 +
   2.206 +
   2.207 +    // Test every divisor between -100 and 100.
   2.208 +    for (int i = -100; i <= 100; i++) {
   2.209 +      test_divisor(i, apploader);
   2.210 +    }
   2.211 +
   2.212 +    // Try a few divisors outside the typical range.
   2.213 +    // The values below have been observed in rt.jar.
   2.214 +    test_divisor(101, apploader);
   2.215 +    test_divisor(400, apploader);
   2.216 +    test_divisor(1000, apploader);
   2.217 +    test_divisor(3600, apploader);
   2.218 +    test_divisor(9973, apploader);
   2.219 +    test_divisor(86400, apploader);
   2.220 +    test_divisor(1000000, apploader);
   2.221 +  }
   2.222 +
   2.223 +}
     3.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     3.2 +++ b/test/compiler/6800154/Test6800154.java	Fri Feb 13 09:09:35 2009 -0800
     3.3 @@ -0,0 +1,109 @@
     3.4 +/*
     3.5 + * Copyright 2009 Sun Microsystems, Inc.  All Rights Reserved.
     3.6 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
     3.7 + *
     3.8 + * This code is free software; you can redistribute it and/or modify it
     3.9 + * under the terms of the GNU General Public License version 2 only, as
    3.10 + * published by the Free Software Foundation.
    3.11 + *
    3.12 + * This code is distributed in the hope that it will be useful, but WITHOUT
    3.13 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
    3.14 + * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
    3.15 + * version 2 for more details (a copy is included in the LICENSE file that
    3.16 + * accompanied this code).
    3.17 + *
    3.18 + * You should have received a copy of the GNU General Public License version
    3.19 + * 2 along with this work; if not, write to the Free Software Foundation,
    3.20 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
    3.21 + *
    3.22 + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
    3.23 + * CA 95054 USA or visit www.sun.com if you need additional information or
    3.24 + * have any questions.
    3.25 + */
    3.26 +
    3.27 +/**
    3.28 + * @test
    3.29 + * @bug 6800154
    3.30 + * @summary Add comments to long_by_long_mulhi() for better understandability
    3.31 + *
    3.32 + * @run main/othervm -Xcomp -XX:CompileOnly=Test6800154.divcomp Test6800154
    3.33 + */
    3.34 +
    3.35 +import java.net.URLClassLoader;
    3.36 +
    3.37 +public class Test6800154 implements Runnable {
    3.38 +    static final long[] DIVIDENDS = {
    3.39 +        0,
    3.40 +        1,
    3.41 +        2,
    3.42 +        1423487,
    3.43 +        4444441,
    3.44 +        4918923241323L,
    3.45 +        -1,
    3.46 +        -24351,
    3.47 +        0x3333,
    3.48 +        0x0000000080000000L,
    3.49 +        0x7fffffffffffffffL,
    3.50 +        0x8000000000000000L
    3.51 +    };
    3.52 +
    3.53 +    static final long[] DIVISORS = {
    3.54 +        1,
    3.55 +        2,
    3.56 +        17,
    3.57 +        12342,
    3.58 +        24123,
    3.59 +        143444,
    3.60 +        123444442344L,
    3.61 +        -1,
    3.62 +        -2,
    3.63 +        -4423423234231423L,
    3.64 +        0x0000000080000000L,
    3.65 +        0x7fffffffffffffffL,
    3.66 +        0x8000000000000000L
    3.67 +    };
    3.68 +
    3.69 +    // Initialize DIVISOR so that it is final in this class.
    3.70 +    static final long DIVISOR;
    3.71 +
    3.72 +    static {
    3.73 +        long value = 0;
    3.74 +        try {
    3.75 +            value = Long.decode(System.getProperty("divisor"));
    3.76 +        } catch (Throwable e) {
    3.77 +        }
    3.78 +        DIVISOR = value;
    3.79 +    }
    3.80 +
    3.81 +    public static void main(String[] args) throws Exception
    3.82 +    {
    3.83 +        Class cl = Class.forName("Test6800154");
    3.84 +        URLClassLoader apploader = (URLClassLoader) cl.getClassLoader();
    3.85 +
    3.86 +        // Iterate over all divisors.
    3.87 +        for (int i = 0; i < DIVISORS.length; i++) {
    3.88 +            System.setProperty("divisor", "" + DIVISORS[i]);
    3.89 +            ClassLoader loader = new URLClassLoader(apploader.getURLs(), apploader.getParent());
    3.90 +            Class c = loader.loadClass("Test6800154");
    3.91 +            Runnable r = (Runnable) c.newInstance();
    3.92 +            r.run();
    3.93 +        }
    3.94 +    }
    3.95 +
    3.96 +    public void run()
    3.97 +    {
    3.98 +        // Iterate over all dividends.
    3.99 +        for (int i = 0; i < DIVIDENDS.length; i++) {
   3.100 +            long dividend = DIVIDENDS[i];
   3.101 +
   3.102 +            long expected = divint(dividend);
   3.103 +            long result = divcomp(dividend);
   3.104 +
   3.105 +            if (result != expected)
   3.106 +                throw new InternalError(dividend + " / " + DIVISOR + " failed: " + result + " != " + expected);
   3.107 +        }
   3.108 +    }
   3.109 +
   3.110 +    static long divint(long a)  { return a / DIVISOR; }
   3.111 +    static long divcomp(long a) { return a / DIVISOR; }
   3.112 +}

mercurial