| ... | @@ -2,6 +2,7 @@ const std = @import("std"); | ... | @@ -2,6 +2,7 @@ const std = @import("std"); |
| 2 | const builtin = @import("builtin"); | 2 | const builtin = @import("builtin"); |
| 3 | const is_test = builtin.is_test; | 3 | const is_test = builtin.is_test; |
| 4 | const Log2Int = std.math.Log2Int; | 4 | const Log2Int = std.math.Log2Int; |
| | 5 | const HalveInt = @import("common.zig").HalveInt; |
| 5 | | 6 | |
| 6 | const lo = switch (builtin.cpu.arch.endian()) { | 7 | const lo = switch (builtin.cpu.arch.endian()) { |
| 7 | .Big => 1, | 8 | .Big => 1, |
| ... | @@ -9,19 +10,10 @@ const lo = switch (builtin.cpu.arch.endian()) { | ... | @@ -9,19 +10,10 @@ const lo = switch (builtin.cpu.arch.endian()) { |
| 9 | }; | 10 | }; |
| 10 | const hi = 1 - lo; | 11 | const hi = 1 - lo; |
| 11 | | 12 | |
| 12 | fn HalfInt(comptime T: type) type { | 13 | // Let _u1 and _u0 be the high and low limbs of U respectively. |
| 13 | std.debug.assert(@typeInfo(T) == .Int); | 14 | // Returns U / v_ and sets r = U % v_. |
| 14 | std.debug.assert(@bitSizeOf(T) % 2 == 0); | | |
| 15 | return std.meta.Int(.unsigned, @bitSizeOf(T) / 2); | | |
| 16 | } | | |
| 17 | | | |
| 18 | // Performs division of a double-word specified in its single-word components. Most commonly used | | |
| 19 | // for computing u128 bit divisions in terms of 64-bit integers. | | |
| 20 | // | | |
| 21 | // q = U / v | | |
| 22 | // r = U % v | | |
| 23 | // where U = (u1 | u0) | | |
| 24 | fn divwide_generic(comptime T: type, _u1: T, _u0: T, v_: T, r: *T) T { | 15 | fn divwide_generic(comptime T: type, _u1: T, _u0: T, v_: T, r: *T) T { |
| | 16 | const HalfT = HalveInt(T, false).HalfT; |
| 25 | @setRuntimeSafety(is_test); | 17 | @setRuntimeSafety(is_test); |
| 26 | var v = v_; | 18 | var v = v_; |
| 27 | | 19 | |
| ... | @@ -43,11 +35,11 @@ fn divwide_generic(comptime T: type, _u1: T, _u0: T, v_: T, r: *T) T { | ... | @@ -43,11 +35,11 @@ fn divwide_generic(comptime T: type, _u1: T, _u0: T, v_: T, r: *T) T { |
| 43 | | 35 | |
| 44 | // Break divisor up into two 32-bit digits | 36 | // Break divisor up into two 32-bit digits |
| 45 | const vn1 = v >> (@bitSizeOf(T) / 2); | 37 | const vn1 = v >> (@bitSizeOf(T) / 2); |
| 46 | const vn0 = v & std.math.maxInt(HalfInt(T)); | 38 | const vn0 = v & std.math.maxInt(HalfT); |
| 47 | | 39 | |
| 48 | // Break right half of dividend into two digits | 40 | // Break right half of dividend into two digits |
| 49 | const un1 = un10 >> (@bitSizeOf(T) / 2); | 41 | const un1 = un10 >> (@bitSizeOf(T) / 2); |
| 50 | const un0 = un10 & std.math.maxInt(HalfInt(T)); | 42 | const un0 = un10 & std.math.maxInt(HalfT); |
| 51 | | 43 | |
| 52 | // Compute the first quotient digit, q1 | 44 | // Compute the first quotient digit, q1 |
| 53 | var q1 = un64 / vn1; | 45 | var q1 = un64 / vn1; |
| ... | @@ -79,7 +71,7 @@ fn divwide_generic(comptime T: type, _u1: T, _u0: T, v_: T, r: *T) T { | ... | @@ -79,7 +71,7 @@ fn divwide_generic(comptime T: type, _u1: T, _u0: T, v_: T, r: *T) T { |
| 79 | | 71 | |
| 80 | fn divwide(comptime T: type, _u1: T, _u0: T, v: T, r: *T) T { | 72 | fn divwide(comptime T: type, _u1: T, _u0: T, v: T, r: *T) T { |
| 81 | @setRuntimeSafety(is_test); | 73 | @setRuntimeSafety(is_test); |
| 82 | if (T == u64 and builtin.target.cpu.arch == .x86_64) { | 74 | if (T == u64 and builtin.target.cpu.arch == .x86_64 and builtin.target.os.tag != .windows) { |
| 83 | var rem: T = undefined; | 75 | var rem: T = undefined; |
| 84 | const quo = asm ( | 76 | const quo = asm ( |
| 85 | \\divq %[v] | 77 | \\divq %[v] |
| ... | @@ -96,10 +88,10 @@ fn divwide(comptime T: type, _u1: T, _u0: T, v: T, r: *T) T { | ... | @@ -96,10 +88,10 @@ fn divwide(comptime T: type, _u1: T, _u0: T, v: T, r: *T) T { |
| 96 | } | 88 | } |
| 97 | } | 89 | } |
| 98 | | 90 | |
| 99 | // return q = a / b, *r = a % b | 91 | // Returns a_ / b_ and sets maybe_rem = a_ % b. |
| 100 | pub fn udivmod(comptime T: type, a_: T, b_: T, maybe_rem: ?*T) T { | 92 | pub fn udivmod(comptime T: type, a_: T, b_: T, maybe_rem: ?*T) T { |
| 101 | @setRuntimeSafety(is_test); | 93 | @setRuntimeSafety(is_test); |
| 102 | const HalfT = HalfInt(T); | 94 | const HalfT = HalveInt(T, false).HalfT; |
| 103 | const SignedT = std.meta.Int(.signed, @bitSizeOf(T)); | 95 | const SignedT = std.meta.Int(.signed, @bitSizeOf(T)); |
| 104 | | 96 | |
| 105 | if (b_ > a_) { | 97 | if (b_ > a_) { |
| ... | @@ -141,8 +133,8 @@ pub fn udivmod(comptime T: type, a_: T, b_: T, maybe_rem: ?*T) T { | ... | @@ -141,8 +133,8 @@ pub fn udivmod(comptime T: type, a_: T, b_: T, maybe_rem: ?*T) T { |
| 141 | for (0..shift + 1) |_| { | 133 | for (0..shift + 1) |_| { |
| 142 | q[lo] <<= 1; | 134 | q[lo] <<= 1; |
| 143 | // Branchless version of: | 135 | // Branchless version of: |
| 144 | // if (a >= b) { | 136 | // if (af >= bf) { |
| 145 | // a -= b; | 137 | // af -= bf; |
| 146 | // q[lo] |= 1; | 138 | // q[lo] |= 1; |
| 147 | // } | 139 | // } |
| 148 | const s = @bitCast(SignedT, bf -% af -% 1) >> (@bitSizeOf(T) - 1); | 140 | const s = @bitCast(SignedT, bf -% af -% 1) >> (@bitSizeOf(T) - 1); |