diff options
Diffstat (limited to 'libphobos/libdruntime/core/int128.d')
-rw-r--r-- | libphobos/libdruntime/core/int128.d | 156 |
1 files changed, 91 insertions, 65 deletions
diff --git a/libphobos/libdruntime/core/int128.d b/libphobos/libdruntime/core/int128.d index 2f628c03138..e4326fd54c3 100644 --- a/libphobos/libdruntime/core/int128.d +++ b/libphobos/libdruntime/core/int128.d @@ -18,15 +18,26 @@ alias I = long; alias U = ulong; enum Ubits = uint(U.sizeof * 8); -align(16) struct Cent +version (X86_64) private enum Cent_alignment = 16; +else private enum Cent_alignment = (size_t.sizeof * 2); + +align(Cent_alignment) struct Cent { - U lo; // low 64 bits - U hi; // high 64 bits + version (LittleEndian) + { + U lo; // low 64 bits + U hi; // high 64 bits + } + else + { + U hi; // high 64 bits + U lo; // low 64 bits + } } -enum One = Cent(1); -enum Zero = Cent(); -enum MinusOne = neg(One); +enum Cent One = { lo:1 }; +enum Cent Zero = { lo:0 }; +enum Cent MinusOne = neg(One); /***************************** * Test against 0 @@ -320,7 +331,8 @@ Cent ror(Cent c, uint n) pure Cent and(Cent c1, Cent c2) { - return Cent(c1.lo & c2.lo, c1.hi & c2.hi); + const Cent ret = { lo:c1.lo & c2.lo, hi:c1.hi & c2.hi }; + return ret; } /**************************** @@ -334,7 +346,8 @@ Cent and(Cent c1, Cent c2) pure Cent or(Cent c1, Cent c2) { - return Cent(c1.lo | c2.lo, c1.hi | c2.hi); + const Cent ret = { lo:c1.lo | c2.lo, hi:c1.hi | c2.hi }; + return ret; } /**************************** @@ -348,7 +361,8 @@ Cent or(Cent c1, Cent c2) pure Cent xor(Cent c1, Cent c2) { - return Cent(c1.lo ^ c2.lo, c1.hi ^ c2.hi); + const Cent ret = { lo:c1.lo ^ c2.lo, hi:c1.hi ^ c2.hi }; + return ret; } /**************************** @@ -363,7 +377,8 @@ pure Cent add(Cent c1, Cent c2) { U r = cast(U)(c1.lo + c2.lo); - return Cent(r, cast(U)(c1.hi + c2.hi + (r < c1.lo))); + const Cent ret = { lo:r, hi:cast(U)(c1.hi + c2.hi + (r < c1.lo)) }; + return ret; } /**************************** @@ -419,9 +434,9 @@ Cent mul(Cent c1, Cent c2) const c1h1 = c1.hi >> mulshift; r3 = c1h1 * c2l0 + (r3 & mulmask); - return Cent((r0 & mulmask) + (r1 & mulmask) * (mulmask + 1), - (r2 & mulmask) + (r3 & mulmask) * (mulmask + 1)); - + const Cent ret = { lo:(r0 & mulmask) + (r1 & mulmask) * (mulmask + 1), + hi:(r2 & mulmask) + (r3 & mulmask) * (mulmask + 1) }; + return ret; } @@ -523,8 +538,10 @@ Cent udivmod(Cent c1, Cent c2, out Cent modulus) if (c1.hi == 0 && c2.hi == 0) { // Single precision divide - modulus = Cent(c1.lo % c2.lo); - return Cent(c1.lo / c2.lo); + const Cent rem = { lo:c1.lo % c2.lo }; + modulus = rem; + const Cent ret = { lo:c1.lo / c2.lo }; + return ret; } if (c1.hi == 0) { @@ -539,10 +556,11 @@ Cent udivmod(Cent c1, Cent c2, out Cent modulus) const q1 = (c1.hi < c2.lo) ? 0 : (c1.hi / c2.lo); if (q1) c1.hi = c1.hi % c2.lo; - U rem; - const q0 = udivmod128_64(c1, c2.lo, rem); - modulus = Cent(rem); - return Cent(q0, q1); + Cent rem; + const q0 = udivmod128_64(c1, c2.lo, rem.lo); + modulus = rem; + const Cent ret = { lo:q0, hi:q1 }; + return ret; } // Full cent precision division. @@ -560,10 +578,10 @@ Cent udivmod(Cent c1, Cent c2, out Cent modulus) // Get quotient from divide unsigned operation. U rem_ignored; - const q1 = udivmod128_64(u1, v1, rem_ignored); + const Cent q1 = { lo:udivmod128_64(u1, v1, rem_ignored) }; // Undo normalization and division of c1 by 2. - Cent quotient = shr(shl(Cent(q1), shift), 63); + Cent quotient = shr(shl(q1, shift), 63); // Make quotient correct or too small by 1 if (tst(quotient)) @@ -770,44 +788,44 @@ version (unittest) unittest { - const C0 = Zero; - const C1 = One; - const C2 = Cent(2); - const C3 = Cent(3); - const C5 = Cent(5); - const C10 = Cent(10); - const C20 = Cent(20); - const C30 = Cent(30); - const C100 = Cent(100); - - const Cm1 = neg(One); - const Cm3 = neg(C3); - const Cm10 = neg(C10); - - const C3_1 = Cent(1,3); - const C3_2 = Cent(2,3); - const C4_8 = Cent(8, 4); - const C5_0 = Cent(0, 5); - const C7_1 = Cent(1,7); - const C7_9 = Cent(9,7); - const C9_3 = Cent(3,9); - const C10_0 = Cent(0,10); - const C10_1 = Cent(1,10); - const C10_3 = Cent(3,10); - const C11_3 = Cent(3,11); - const C20_0 = Cent(0,20); - const C90_30 = Cent(30,90); - - const Cm10_0 = inc(com(C10_0)); // Cent(0, -10); - const Cm10_1 = inc(com(C10_1)); // Cent(-1, -11); - const Cm10_3 = inc(com(C10_3)); // Cent(-3, -11); - const Cm20_0 = inc(com(C20_0)); // Cent(0, -20); - - enum Cs_3 = Cent(3, I.min); - - const Cbig_1 = Cent(0xa3ccac1832952398, 0xc3ac542864f652f8); - const Cbig_2 = Cent(0x5267b85f8a42fc20, 0); - const Cbig_3 = Cent(0xf0000000ffffffff, 0); + const Cent C0 = Zero; + const Cent C1 = One; + const Cent C2 = { lo:2 }; + const Cent C3 = { lo:3 }; + const Cent C5 = { lo:5 }; + const Cent C10 = { lo:10 }; + const Cent C20 = { lo:20 }; + const Cent C30 = { lo:30 }; + const Cent C100 = { lo:100 }; + + const Cent Cm1 = neg(One); + const Cent Cm3 = neg(C3); + const Cent Cm10 = neg(C10); + + const Cent C3_1 = { lo:1, hi:3 }; + const Cent C3_2 = { lo:2, hi:3 }; + const Cent C4_8 = { lo:8, hi:4 }; + const Cent C5_0 = { lo:0, hi:5 }; + const Cent C7_1 = { lo:1, hi:7 }; + const Cent C7_9 = { lo:9, hi:7 }; + const Cent C9_3 = { lo:3, hi:9 }; + const Cent C10_0 = { lo:0, hi:10 }; + const Cent C10_1 = { lo:1, hi:10 }; + const Cent C10_3 = { lo:3, hi:10 }; + const Cent C11_3 = { lo:3, hi:11 }; + const Cent C20_0 = { lo:0, hi:20 }; + const Cent C90_30 = { lo:30, hi:90 }; + + const Cent Cm10_0 = inc(com(C10_0)); // Cent(lo=0, hi=-10); + const Cent Cm10_1 = inc(com(C10_1)); // Cent(lo=-1, hi=-11); + const Cent Cm10_3 = inc(com(C10_3)); // Cent(lo=-3, hi=-11); + const Cent Cm20_0 = inc(com(C20_0)); // Cent(lo=0, hi=-20); + + enum Cent Cs_3 = { lo:3, hi:I.min }; + + const Cent Cbig_1 = { lo:0xa3ccac1832952398, hi:0xc3ac542864f652f8 }; + const Cent Cbig_2 = { lo:0x5267b85f8a42fc20, hi:0 }; + const Cent Cbig_3 = { lo:0xf0000000ffffffff, hi:0 }; /************************/ @@ -893,12 +911,20 @@ unittest assert(div(mul(C90_30, C2), C2) == C90_30); assert(div(mul(C90_30, C2), C90_30) == C2); - assert(divmod(Cbig_1, Cbig_2, modulus) == Cent(0x4496aa309d4d4a2f, U.max)); - assert(modulus == Cent(0xd83203d0fdc799b8, U.max)); - assert(udivmod(Cbig_1, Cbig_2, modulus) == Cent(0x5fe0e9bace2bedad, 2)); - assert(modulus == Cent(0x2c923125a68721f8, 0)); - assert(div(Cbig_1, Cbig_3) == Cent(0xbfa6c02b5aff8b86, U.max)); - assert(udiv(Cbig_1, Cbig_3) == Cent(0xd0b7d13b48cb350f, 0)); + const Cent Cb1divb2 = { lo:0x4496aa309d4d4a2f, hi:U.max }; + const Cent Cb1modb2 = { lo:0xd83203d0fdc799b8, hi:U.max }; + assert(divmod(Cbig_1, Cbig_2, modulus) == Cb1divb2); + assert(modulus == Cb1modb2); + + const Cent Cb1udivb2 = { lo:0x5fe0e9bace2bedad, hi:2 }; + const Cent Cb1umodb2 = { lo:0x2c923125a68721f8, hi:0 }; + assert(udivmod(Cbig_1, Cbig_2, modulus) == Cb1udivb2); + assert(modulus == Cb1umodb2); + + const Cent Cb1divb3 = { lo:0xbfa6c02b5aff8b86, hi:U.max }; + const Cent Cb1udivb3 = { lo:0xd0b7d13b48cb350f, hi:0 }; + assert(div(Cbig_1, Cbig_3) == Cb1divb3); + assert(udiv(Cbig_1, Cbig_3) == Cb1udivb3); assert(mul(Cm10, C1) == Cm10); assert(mul(C1, Cm10) == Cm10); |