| ... | @@ -552,21 +552,29 @@ pub const Mutable = struct { | ... | @@ -552,21 +552,29 @@ pub const Mutable = struct { |
| 552 | r.positive = a.positive; | 552 | r.positive = a.positive; |
| 553 | } | 553 | } |
| 554 | | 554 | |
| 555 | /// r = a | b | 555 | /// r = a | b under 2s complement semantics. |
| 556 | /// r may alias with a or b. | 556 | /// r may alias with a or b. |
| 557 | /// | 557 | /// |
| 558 | /// a and b are zero-extended to the longer of a or b. | 558 | /// a and b are zero-extended to the longer of a or b. |
| 559 | /// | 559 | /// |
| 560 | /// Asserts that r has enough limbs to store the result. Upper bound is `math.max(a.limbs.len, b.limbs.len)`. | 560 | /// Asserts that r has enough limbs to store the result. Upper bound is `math.max(a.limbs.len, b.limbs.len)`. |
| 561 | pub fn bitOr(r: *Mutable, a: Const, b: Const) void { | 561 | pub fn bitOr(r: *Mutable, a: Const, b: Const) void { |
| 562 | if (a.limbs.len > b.limbs.len) { | 562 | // Trivial cases, llsignedor does not support zero. |
| 563 | llor(r.limbs[0..], a.limbs[0..a.limbs.len], b.limbs[0..b.limbs.len]); | 563 | if (a.eqZero()) { |
| 564 | r.len = a.limbs.len; | 564 | r.copy(b); |
| | 565 | return; |
| | 566 | } else if (b.eqZero()) { |
| | 567 | r.copy(a); |
| | 568 | return; |
| | 569 | } |
| | 570 | |
| | 571 | if (a.limbs.len >= b.limbs.len) { |
| | 572 | r.positive = llsignedor(r.limbs, a.limbs, a.positive, b.limbs, b.positive); |
| | 573 | r.normalize(a.limbs.len); |
| 565 | } else { | 574 | } else { |
| 566 | llor(r.limbs[0..], b.limbs[0..b.limbs.len], a.limbs[0..a.limbs.len]); | 575 | r.positive = llsignedor(r.limbs, b.limbs, b.positive, a.limbs, a.positive); |
| 567 | r.len = b.limbs.len; | 576 | r.normalize(b.limbs.len); |
| 568 | } | 577 | } |
| 569 | r.positive = a.positive or b.positive; | | |
| 570 | } | 578 | } |
| 571 | | 579 | |
| 572 | /// r = a & b | 580 | /// r = a & b |
| ... | @@ -2236,17 +2244,119 @@ fn llshr(r: []Limb, a: []const Limb, shift: usize) void { | ... | @@ -2236,17 +2244,119 @@ fn llshr(r: []Limb, a: []const Limb, shift: usize) void { |
| 2236 | } | 2244 | } |
| 2237 | } | 2245 | } |
| 2238 | | 2246 | |
| 2239 | fn llor(r: []Limb, a: []const Limb, b: []const Limb) void { | 2247 | fn llsignedor(r: []Limb, a: []const Limb, a_positive: bool, b: []const Limb, b_positive: bool) bool { |
| 2240 | @setRuntimeSafety(debug_safety); | 2248 | @setRuntimeSafety(debug_safety); |
| 2241 | assert(r.len >= a.len); | 2249 | assert(r.len >= a.len); |
| 2242 | assert(a.len >= b.len); | 2250 | assert(a.len >= b.len); |
| 2243 | | 2251 | |
| 2244 | var i: usize = 0; | 2252 | if (a_positive and b_positive) { |
| 2245 | while (i < b.len) : (i += 1) { | 2253 | // Trivial case, result is positive., |
| 2246 | r[i] = a[i] | b[i]; | 2254 | var i: usize = 0; |
| 2247 | } | 2255 | while (i < b.len) : (i += 1) { |
| 2248 | while (i < a.len) : (i += 1) { | 2256 | r[i] = a[i] | b[i]; |
| 2249 | r[i] = a[i]; | 2257 | } |
| | 2258 | while (i < a.len) : (i += 1) { |
| | 2259 | r[i] = a[i]; |
| | 2260 | } |
| | 2261 | |
| | 2262 | return true; |
| | 2263 | } else if (!a_positive and b_positive) { |
| | 2264 | // r = (--a) | b |
| | 2265 | // = ~(-a - 1) | b |
| | 2266 | // = ~(-a - 1) | ~~b |
| | 2267 | // = ~((-a - 1) & ~b) |
| | 2268 | // = -(((-a - 1) & ~b) + 1) |
| | 2269 | // result is negative. |
| | 2270 | |
| | 2271 | var i: usize = 0; |
| | 2272 | var a_borrow: u1 = 1; |
| | 2273 | var r_carry: u1 = 1; |
| | 2274 | |
| | 2275 | while (i < b.len) : (i += 1) { |
| | 2276 | var a_limb: Limb = undefined; |
| | 2277 | a_borrow = @boolToInt(@subWithOverflow(Limb, a[i], a_borrow, &a_limb)); |
| | 2278 | |
| | 2279 | r[i] = a_limb & ~b[i]; |
| | 2280 | r_carry = @boolToInt(@addWithOverflow(Limb, r[i], r_carry, &r[i])); |
| | 2281 | } |
| | 2282 | |
| | 2283 | // With b = 0, we get (-a - 1) & ~0 = -a - 1. |
| | 2284 | while (i < a.len) : (i += 1) { |
| | 2285 | a_borrow = @boolToInt(@subWithOverflow(Limb, a[i], a_borrow, &r[i])); |
| | 2286 | r_carry = @boolToInt(@addWithOverflow(Limb, r[i], r_carry, &r[i])); |
| | 2287 | } |
| | 2288 | |
| | 2289 | assert(a_borrow == 0); // a was 0. |
| | 2290 | |
| | 2291 | // Can never overflow because a_borrow would need to equal 1. |
| | 2292 | assert(r_carry == 0); |
| | 2293 | |
| | 2294 | return false; |
| | 2295 | } else if (a_positive and !b_positive) { |
| | 2296 | // r = a | (--b) |
| | 2297 | // = a | ~(-b - 1) |
| | 2298 | // = ~~a | ~(-b - 1) |
| | 2299 | // = ~(~a & (-b - 1)) |
| | 2300 | // = -((~a & (-b - 1)) + 1) |
| | 2301 | // result is negative. |
| | 2302 | |
| | 2303 | var i: usize = 0; |
| | 2304 | var b_borrow: u1 = 1; |
| | 2305 | var r_carry: u1 = 1; |
| | 2306 | |
| | 2307 | while (i < b.len) : (i += 1) { |
| | 2308 | var b_limb: Limb = undefined; |
| | 2309 | b_borrow = @boolToInt(@subWithOverflow(Limb, b[i], b_borrow, &b_limb)); |
| | 2310 | |
| | 2311 | r[i] = ~a[i] & b_limb; |
| | 2312 | r_carry = @boolToInt(@addWithOverflow(Limb, r[i], r_carry, &r[i])); |
| | 2313 | } |
| | 2314 | |
| | 2315 | // b is at least 1, so this should never underflow. |
| | 2316 | assert(b_borrow == 0); // b was 0 |
| | 2317 | |
| | 2318 | // Can never overflow because in order for b_limb to be maxInt(Limb), |
| | 2319 | // b_borrow would need to equal 1. |
| | 2320 | assert(r_carry == 0); |
| | 2321 | |
| | 2322 | // With b = 0 and b_borrow = 0, we get ~a & (-0 - 0) = ~a & 0 = 0. |
| | 2323 | mem.set(Limb, r[i..a.len], 0); |
| | 2324 | |
| | 2325 | return false; |
| | 2326 | } else { |
| | 2327 | // r = (--a) | (--b) |
| | 2328 | // = ~(-a - 1) | ~(-b - 1) |
| | 2329 | // = ~((-a - 1) & (-b - 1)) |
| | 2330 | // = -(~(~((-a - 1) & (-b - 1))) + 1) |
| | 2331 | // = -((-a - 1) & (-b - 1) + 1) |
| | 2332 | // result is negative. |
| | 2333 | |
| | 2334 | var i: usize = 0; |
| | 2335 | var a_borrow: u1 = 1; |
| | 2336 | var b_borrow: u1 = 1; |
| | 2337 | var r_carry: u1 = 1; |
| | 2338 | |
| | 2339 | while (i < b.len) : (i += 1) { |
| | 2340 | var a_limb: Limb = undefined; |
| | 2341 | a_borrow = @boolToInt(@subWithOverflow(Limb, a[i], a_borrow, &a_limb)); |
| | 2342 | |
| | 2343 | var b_limb: Limb = undefined; |
| | 2344 | b_borrow = @boolToInt(@subWithOverflow(Limb, b[i], b_borrow, &b_limb)); |
| | 2345 | |
| | 2346 | r[i] = a_limb & b_limb; |
| | 2347 | r_carry = @boolToInt(@addWithOverflow(Limb, r[i], r_carry, &r[i])); |
| | 2348 | } |
| | 2349 | |
| | 2350 | // b is at least 1, so this should never underflow. |
| | 2351 | assert(b_borrow == 0); // b was 0 |
| | 2352 | |
| | 2353 | // Can never overflow because in order for b_limb to be maxInt(Limb), |
| | 2354 | // b_borrow would need to equal 1. |
| | 2355 | assert(r_carry == 0); |
| | 2356 | |
| | 2357 | // With b = 0 and b_borrow = 0 we get (-a - 1) & (-0 - 0) = (-a - 1) & 0 = 0. |
| | 2358 | mem.set(Limb, r[i..a.len], 0); |
| | 2359 | return false; |
| 2250 | } | 2360 | } |
| 2251 | } | 2361 | } |
| 2252 | | 2362 | |