1 // -*- Mode: Java; indent-tabs-mode: t; tab-width: 4 -*-
2 // ---------------------------------------------------------------------------
4 // Copyright (C) Stephanie Gawroriski <xer@multiphasicapps.net>
5 // ---------------------------------------------------------------------------
6 // SquirrelJME is under the GNU General Public License v3+, or later.
7 // See license.mkd for licensing and copyright information.
8 // ---------------------------------------------------------------------------
10 package cc
.squirreljme
.jvm
;
12 import cc
.squirreljme
.jvm
.mle
.MathShelf
;
13 import cc
.squirreljme
.runtime
.cldc
.annotation
.SquirrelJMEVendorApi
;
14 import cc
.squirreljme
.runtime
.cldc
.debug
.Debugging
;
17 * Software math operations on 64-bit integer types.
22 @SuppressWarnings("MagicNumber")
23 public final class SoftLong
45 public static long add(int __al
, int __ah
, int __bl
, int __bh
)
47 // Add the higher/lower parts
51 // If the low addition carried a bit over, then set that bit in the
53 if ((cl
+ 0x80000000) < (__al
+ 0x80000000))
57 return MathShelf
.longPack(cl
, ch
);
71 public static long and(int __al
, int __ah
, int __bl
, int __bh
)
73 return MathShelf
.longPack(__al
& __bl
, __ah
& __bh
);
77 * Compares two values.
87 public static int cmp(int __al
, int __ah
, int __bl
, int __bh
)
89 // Compare high values firsts
95 // Compare low values with unsigned comparison
96 __al
+= Integer
.MIN_VALUE
;
97 __bl
+= Integer
.MIN_VALUE
;
100 else if (__al
> __bl
)
106 * Divides two values.
109 * @param __ah A high.
111 * @param __bh B high.
112 * @return The result.
115 @SquirrelJMEVendorApi
116 public static long div(int __al
, int __ah
, int __bl
, int __bh
)
119 if (__bh
== 0 && __bl
== 0)
120 throw new ArithmeticException();
122 return SoftLong
.__div(false, __al
, __ah
, __bl
, __bh
);
126 * Multiplies two long values.
129 * @param __ah A high.
131 * @param __bh B high.
132 * @return The result.
135 @SquirrelJMEVendorApi
136 public static long mul(int __al
, int __ah
, int __bl
, int __bh
)
138 // Are both sides negative?
139 if (((__ah
& __bh
) & 0x8000_
0000) != 0)
141 // Negate and check for overflow
147 // Negate and check for overflow
154 return SoftLong
.__mul(__al
, __ah
, __bl
, __bh
);
157 // Perform the calculation
158 return SoftLong
.__mul(__al
, __ah
, __bl
, __bh
);
165 * @param __ah A high.
166 * @return The result.
169 @SquirrelJMEVendorApi
170 public static long neg(int __al
, int __ah
)
172 // Negate and check for overflow
179 return MathShelf
.longPack(__al
, __ah
);
186 * @param __ah A high.
188 * @param __bh B high.
189 * @return The result.
192 @SquirrelJMEVendorApi
193 public static long or(int __al
, int __ah
, int __bl
, int __bh
)
195 return MathShelf
.longPack(__al
| __bl
, __ah
| __bh
);
199 * Remainders a value.
202 * @param __ah A high.
204 * @param __bh B high.
205 * @return The result.
208 @SquirrelJMEVendorApi
209 public static long rem(int __al
, int __ah
, int __bl
, int __bh
)
212 if (__bh
== 0 && __bl
== 0)
213 throw new ArithmeticException();
215 return SoftLong
.__div(true, __al
, __ah
, __bl
, __bh
);
219 * Shifts value left by bits.
222 * @param __ah A high.
223 * @param __s Shift amount.
224 * @return The result.
227 @SquirrelJMEVendorApi
228 public static long shl(int __al
, int __ah
, int __s
)
230 // Mask the shift amount
235 return MathShelf
.longPack(__al
, __ah
);
237 // Shifting all the low bits to the high bits
239 return MathShelf
.longPack(0, __al
<< (__s
- 32));
241 // Merge of bits (shift in range of 1-31)
242 return MathShelf
.longPack((__al
<< __s
),
243 (__ah
<< __s
) | (__al
>>> (32 - __s
)));
247 * Shifts value right by bits.
250 * @param __ah A high.
251 * @param __s Shift amount.
252 * @return The result.
255 @SquirrelJMEVendorApi
256 public static long shr(int __al
, int __ah
, int __s
)
258 // Mask the shift amount
263 return MathShelf
.longPack(__al
, __ah
);
265 // Shifting all the high bits low
267 return MathShelf
.longPack(__ah
>> (__s
- 32),
268 (__ah
& 0x80000000) >> 31);
270 // Merge of bits (shift in range of 1-31)
271 return MathShelf
.longPack((__ah
<< (32 - __s
)) | (__al
>>> __s
),
279 * @param __ah A high.
281 * @param __bh B high.
282 * @return The result.
285 @SquirrelJMEVendorApi
286 public static long sub(int __al
, int __ah
, int __bl
, int __bh
)
288 // The same as add, but the second operand is negated
289 // Negate and check for overflow
295 // Add the higher/lower parts
296 int ch
= __ah
+ __bh
;
297 int cl
= __al
+ __bl
;
299 // If the low addition carried a bit over, then set that bit in the
301 if ((cl
+ 0x80000000) < (__al
+ 0x80000000))
305 return MathShelf
.longPack(cl
, ch
);
309 * Converts to double.
311 * @param __al Low value.
312 * @param __ah High value.
313 * @return The result.
316 @SquirrelJMEVendorApi
317 public static double toDouble(int __al
, int __ah
)
319 throw Debugging
.todo();
326 * @param __ah A high.
327 * @return The result.
330 @SquirrelJMEVendorApi
331 public static float toFloat(int __al
, int __ah
)
333 throw Debugging
.todo();
337 * Converts to integer.
340 * @param __ah A high.
341 * @return The result.
344 @SquirrelJMEVendorApi
345 public static int toInteger(int __al
, @SuppressWarnings("unused") int __ah
)
347 // Just return the low order bits
352 * Shifts value bits right unsigned.
355 * @param __ah A high.
356 * @param __s Shift amount.
357 * @return The result.
360 @SquirrelJMEVendorApi
361 public static long ushr(int __al
, int __ah
, int __s
)
363 // Mask the shift amount
368 return MathShelf
.longPack(__al
, __ah
);
370 // Shifting all the high bits low
372 return MathShelf
.longPack(__ah
>>> (__s
- 32), 0);
374 // Merge of bits (shift in range of 1-31)
375 return MathShelf
.longPack((__ah
<< (32 - __s
)) | (__al
>>> __s
),
383 * @param __ah A high.
385 * @param __bh B high.
386 * @return The result.
389 @SquirrelJMEVendorApi
390 public static long xor(int __al
, int __ah
, int __bl
, int __bh
)
392 return MathShelf
.longPack(__al ^ __bl
, __ah ^ __bh
);
396 * Divides and remainders two values.
398 * @param __doRem Return the remainder?
399 * @param __nl The numerator, low.
400 * @param __nh The numerator, high.
401 * @param __dl The denominator, low.
402 * @param __dh The denominator, high.
403 * @return The result.
406 @SuppressWarnings("CommentedOutCode")
407 private static long __div(boolean __doRem
, int __nl
, int __nh
,
410 // {@squirreljme.error ZZ4z Divide by zero.}
411 if (__dl
== 0 && __dh
== 0)
412 throw new ArithmeticException("ZZ4z");
414 // Wikipedia (http://en.wikipedia.org/wiki/Division_%28digital%29)
415 // if D == 0 then throw DivisionByZeroException end
416 // Q := 0 # initialize quotient and remainder to zero
418 // for i = n-1...0 do # " where n is no of bits "
419 // R := R << 1 # left-shift R by 1 bit
420 // R(0) := N(i) # set the least-significant bit
421 // # of R equal to bit i of the numerator
427 // long qx = 0, rx = 0;
429 // High and low resultant values
435 // Disallow division by zero
439 // Results in a negative? Only results in such if either side is
441 boolean negNum
= ((__nh
& 0x8000_
0000) != 0);
442 boolean negDem
= ((__dh
& 0x8000_
0000) != 0);
443 boolean isNeg
= (negNum
!= negDem
);
445 // Make the numerator positive, if negative
448 // Negate and check for overflow
455 // Make the denominator positive, if negative
458 // Negate and check for overflow
465 // __dl and __dh for unsigned compare
466 int dlUnsigned
= __dl
+ Integer
.MIN_VALUE
;
467 int dhUnsigned
= __dh
+ Integer
.MIN_VALUE
;
470 for (int i
= 63, hMask
= 0xFFFF_FFFF
, lMask
= 0;
472 i
--, hMask
>>>= 1, lMask
= ((lMask
>> 1) | 0x8000_
0000))
475 // rx &= 0xFFFFFFFFFFFFFFFEL;
480 // rx |= ((__nx >>> i) & 1L); ... only take the lowest bit!
483 // ! rl |= ((__nh >>> (i - 32)) & 0x1);
485 // ! rl |= ((__nl >>> i) & 0x1);
486 // faster using masking:
487 // ! rl |= (((__nh & hMask) >>> i) & 0x1);
488 // ! rl |= (((__nl & lMask) >>> i) & 0x1);
489 rl
|= ((((__nh
& hMask
) | (__nl
& lMask
)) >>> i
) & 0x1);
491 // Unsigned comparison (shift by 0x8000_0000__0000_0000L)
492 // if ((rx + Long.MIN_VALUE) >= (__dx + Long.MIN_VALUE))
493 /*if (SoftLong.cmp(rl, rh + Integer.MIN_VALUE,
494 __dl, __dh + Integer.MIN_VALUE) >= 0)*/
495 int cmp
= (rh
+ Integer
.MIN_VALUE
) - dhUnsigned
;
497 (cmp
> 0 || // Is just a bigger number overall?
498 rl
+ Integer
.MIN_VALUE
>= dlUnsigned
))
501 // The same as add, but the second operand is negated
502 // Negate and check for overflow
504 int bl
= (~__dl
+ 1);
508 // Add the higher/lower parts
512 // If the low addition carried a bit over, then set that bit in
514 if ((cl
+ 0x80000000) < (rl
+ 0x80000000))
522 qh
|= (1 << (i
- 32));
528 // Return the remainder if needed, note the remainder is negative only
529 // if the numerator is negative
531 return (negNum ? SoftLong
.neg(rl
, rh
) :
532 MathShelf
.longPack(rl
, rh
));
534 // Return, normalize negative if needed
535 return (isNeg ? SoftLong
.neg(ql
, qh
) : MathShelf
.longPack(ql
, qh
));
539 * Multiplies two long values, note that this will fail if both A and B
540 * are negative. The values must either be both positive or only one is
544 * @param __ah A high.
546 * @param __bh B high.
547 * @return The result.
550 private static long __mul(int __al
, int __ah
, int __bl
, int __bh
)
553 int a
= (__ah
>>> 16);
554 int b
= (__ah
& 0xFFFF);
555 int c
= (__al
>>> 16);
556 int d
= (__al
& 0xFFFF);
559 int w
= (__bh
>>> 16);
560 int x
= (__bh
& 0xFFFF);
561 int y
= (__bl
>>> 16);
562 int z
= (__bl
& 0xFFFF);
564 // Effectively this is long multiplication
565 // Multiplication in two's complement form is the same in both
566 // signed and unsigned, so we need not worry about signs and just treat
567 // this all as unsigned. Each fragment is 16 of the 64 bits.
570 // ============|===.===,===.===
573 // b_w b_x|b_y.b_z, .
574 // a_w a_x a_y|a_z. , .
575 // ============|===.===,===.===
576 // DISCARD m. n, o. p
578 // Overflow storage, since we want a temporary and we do not want to
579 // make any allocations or otherwise for 64-bit values. This keeps it
580 // all in 32-bit and handles the various situations.
583 // Multiply and add all the parts together
588 // int o = (d * y) + (c * z) + (p >>> 16);
589 int o
= over
+ (d
* y
);
591 o
= (o
& 0xFFFF) + (c
* z
);
594 // int n = (d * x) + (c * y) + (b * z) + (o >>> 16);
595 int n
= over
+ (d
* x
);
597 n
= (n
& 0xFFFF) + (c
* y
);
599 n
= (n
& 0xFFFF) + (b
* z
);
602 // int m = (d * w) + (c * x) + (b * y) + (a * z) + (n >>> 16);
603 // We need not care about overflow here, because it will all be
605 int m
= over
+ (d
* w
) + (c
* x
) + (b
* y
) + (a
* z
);
607 // Combine the resultant parts
608 return MathShelf
.longPack((o
<< 16) | (p
& 0xFFFF),
609 (m
<< 16) | (n
& 0xFFFF));