JDK-8188044 : We need Math.unsignedMultiplyHigh
  • Type: Enhancement
  • Component: core-libs
  • Sub-Component: java.lang
  • Priority: P4
  • Status: Resolved
  • Resolution: Fixed
  • Submitted: 2017-09-27
  • Updated: 2021-10-12
  • Resolved: 2021-07-02
The Version table provides details related to the release that this issue/RFE will be addressed.

Unresolved : Release in which this issue/RFE will be addressed.
Resolved: Release in which this issue/RFE has been resolved.
Fixed : Release in which this issue/RFE has been fixed. The release containing this fix may be available for download as an Early Access Release or a General Availability Release.

To download the current JDK release, click here.
JDK 18
18 b05Fixed
Related Reports
CSR :  
Relates :  
Relates :  
Relates :  
Description
multiplyHigh has been added to java.langMath and its intrinsic implemented, but an unsigned version is more useful for crypto algorithms. While one can fairly easily be calculated from the other, it is slightly slower to make the adjustment and it makes sense to have methods and intrinsics for both.

Comments
Changeset: ca4bea46 Author: Brian Burkhalter <bpb@openjdk.org> Date: 2021-07-02 18:15:35 +0000 URL: https://git.openjdk.java.net/jdk/commit/ca4bea466581217cae2278c98c0fdc568c043818
02-07-2021

I assume we would want to add something to java.lang.Math as we did for multiplyHigh, e.g., @HotSpotIntrinsicCandidate public static long multiplyHighUnsigned(long x, long y) {} and this would be intrinsified as possible on the various platforms. We'd still of course need the Java impl. The content of the method I referred to above is this: private long multiplyHighUnsigned(long x, long y, JavaKind javaKind) { if (javaKind == JavaKind.Int) { long xl = x & 0xFFFFFFFFL; long yl = y & 0xFFFFFFFFL; long r = xl * yl; return (int) (r >>> 32); } else { assert javaKind == JavaKind.Long; long x0 = x & 0xFFFFFFFFL; long x1 = x >>> 32; long y0 = y & 0xFFFFFFFFL; long y1 = y >>> 32; long z0 = x0 * y0; long t = x1 * y0 + (z0 >>> 32); long z1 = t & 0xFFFFFFFFL; long z2 = t >>> 32; z1 += x0 * y1; return x1 * y1 + z2 + (z1 >>> 32); } }
09-10-2019

For the pseudorandom number generation application, what we are after is direct access to an unsignedMultiplyHigh machine instruction on platforms that happen to have one: the goal is speed. (Even better would be direct support for 128-bit arithmetic, but we assume that is further in the future.) If speed is not an issue, then the simple workaround (which we are using for now) is: long unsignedMultiplyHigh(long a, long b) { return Math.multiplyHigh(a, b) + ((a >> 63) & b) + ((b >> 63) & a); } In effect, each operand is added to the result iff the sign bit of the other operand is 1. (See Henry S. Warren, Jr., _Hacker's Delight_ (Second Edition), Addison-Wesley (2013), Section 8-3, p. 175; or see the First Edition, Addison-Wesley (2003), Section 8-3, p. 133.)
09-10-2019

We already have an implementation which could be leveraged: org.graalvm.compiler.core.common.type.IntegerStamp.multiplyHighUnsigned(long x, long y, JavaKind javaKind) {} where javaKind merely indicates int or long.
09-10-2019

Certain algorithms for pseudorandom number generation proposed for JEP 356 (JDK-8193209) would make good use of Math.unsignedMultiplyHigh(long, long). It could be done with Math.multiplyHigh(long, long) but only at the expense of undesirable overhead.
09-10-2019