| ... | @@ -59,8 +59,8 @@ pub fn calcSetStringLimbCount(base: u8, string_len: usize) usize { | ... | @@ -59,8 +59,8 @@ pub fn calcSetStringLimbCount(base: u8, string_len: usize) usize { |
| 59 | } | 59 | } |
| 60 | | 60 | |
| 61 | pub fn calcPowLimbsBufferLen(a_bit_count: usize, y: usize) usize { | 61 | pub fn calcPowLimbsBufferLen(a_bit_count: usize, y: usize) usize { |
| 62 | // The 1 accounts for the multiplication carry | 62 | // The 2 accounts for the minimum space requirement for llmulacc |
| 63 | return 1 + (a_bit_count * y + (limb_bits - 1)) / limb_bits; | 63 | return 2 + (a_bit_count * y + (limb_bits - 1)) / limb_bits; |
| 64 | } | 64 | } |
| 65 | | 65 | |
| 66 | /// a + b * c + *carry, sets carry to the overflow bits | 66 | /// a + b * c + *carry, sets carry to the overflow bits |
| ... | @@ -2205,47 +2205,51 @@ fn llxor(r: []Limb, a: []const Limb, b: []const Limb) void { | ... | @@ -2205,47 +2205,51 @@ fn llxor(r: []Limb, a: []const Limb, b: []const Limb) void { |
| 2205 | | 2205 | |
| 2206 | /// Knuth 4.6.3 | 2206 | /// Knuth 4.6.3 |
| 2207 | fn llpow(r: []Limb, a: []const Limb, b: u32, tmp_limbs: []Limb) void { | 2207 | fn llpow(r: []Limb, a: []const Limb, b: u32, tmp_limbs: []Limb) void { |
| 2208 | mem.copy(Limb, r, a); | 2208 | var tmp1: []Limb = undefined; |
| 2209 | mem.set(Limb, r[a.len..], 0); | 2209 | var tmp2: []Limb = undefined; |
| 2210 | | 2210 | |
| 2211 | // Multiplication requires no aliasing between the operand and the result | 2211 | // Multiplication requires no aliasing between the operand and the result |
| 2212 | // variable, use the output limbs and another temporary set to overcome this | 2212 | // variable, use the output limbs and another temporary set to overcome this |
| 2213 | // limit. | 2213 | // limitation. |
| 2214 | // Note that the order is important in the code below. | 2214 | // The initial assignment makes the result end in `r` so an extra memory |
| 2215 | var list = [_][]Limb{ r, tmp_limbs }; | 2215 | // copy is saved, each 1 flips the index twice so it's a no-op so count the |
| 2216 | var index: usize = 0; | 2216 | // 0. |
| | 2217 | const b_leading_zeros = @intCast(u5, @clz(u32, b)); |
| | 2218 | const exp_zeros = @popCount(u32, ~b) - b_leading_zeros; |
| | 2219 | if (exp_zeros & 1 != 0) { |
| | 2220 | tmp1 = tmp_limbs; |
| | 2221 | tmp2 = r; |
| | 2222 | } else { |
| | 2223 | tmp1 = r; |
| | 2224 | tmp2 = tmp_limbs; |
| | 2225 | } |
| | 2226 | |
| | 2227 | const a_norm = a[0..llnormalize(a)]; |
| | 2228 | |
| | 2229 | mem.copy(Limb, tmp1, a_norm); |
| | 2230 | mem.set(Limb, tmp1[a_norm.len..], 0); |
| 2217 | | 2231 | |
| 2218 | // Scan the exponent as a binary number, from left to right, dropping the | 2232 | // Scan the exponent as a binary number, from left to right, dropping the |
| 2219 | // most significant bit set | 2233 | // most significant bit set. |
| 2220 | var exp = @bitReverse(u32, b) >> (1 + @intCast(u5, @clz(u32, b))); | 2234 | const exp_bits = @intCast(u5, 31 - b_leading_zeros); |
| 2221 | while (exp != 0) : (exp >>= 1) { | 2235 | var exp = @bitReverse(u32, b) >> 1 + b_leading_zeros; |
| | 2236 | |
| | 2237 | var i: u5 = 0; |
| | 2238 | while (i < exp_bits) : (i += 1) { |
| 2222 | // Square | 2239 | // Square |
| 2223 | { | 2240 | { |
| 2224 | const cur_buf = list[index]; | 2241 | mem.set(Limb, tmp2, 0); |
| 2225 | const cur_buf_len = llnormalize(cur_buf); | 2242 | const op = tmp1[0..llnormalize(tmp1)]; |
| 2226 | const cur_buf_out = list[index ^ 1]; | 2243 | llmulacc(null, tmp2, op, op); |
| 2227 | | 2244 | mem.swap([]Limb, &tmp1, &tmp2); |
| 2228 | mem.set(Limb, cur_buf_out, 0); | | |
| 2229 | llmulacc(null, cur_buf_out, cur_buf[0..cur_buf_len], cur_buf[0..cur_buf_len]); | | |
| 2230 | | | |
| 2231 | index ^= 1; | | |
| 2232 | } | 2245 | } |
| 2233 | | 2246 | // Multiply by a |
| 2234 | if ((exp & 1) != 0) { | 2247 | if (exp & 1 != 0) { |
| 2235 | // Multiply | 2248 | mem.set(Limb, tmp2, 0); |
| 2236 | const cur_buf = list[index]; | 2249 | llmulacc(null, tmp2, tmp1[0..llnormalize(tmp1)], a_norm); |
| 2237 | const cur_buf_len = llnormalize(cur_buf); | 2250 | mem.swap([]Limb, &tmp1, &tmp2); |
| 2238 | const cur_buf_out = list[index ^ 1]; | | |
| 2239 | | | |
| 2240 | mem.set(Limb, cur_buf_out, 0); | | |
| 2241 | llmulacc(null, cur_buf_out, cur_buf, a); | | |
| 2242 | | | |
| 2243 | index ^= 1; | | |
| 2244 | } | 2251 | } |
| 2245 | } | 2252 | exp >>= 1; |
| 2246 | | | |
| 2247 | if (index != 0) { | | |
| 2248 | mem.copy(Limb, r, tmp_limbs); | | |
| 2249 | } | 2253 | } |
| 2250 | } | 2254 | } |
| 2251 | | 2255 | |