mirror of
https://github.com/golang/go.git
synced 2025-12-08 06:10:04 +00:00
45 lines
1.2 KiB
Go
45 lines
1.2 KiB
Go
|
|
// Copyright 2024 The Go Authors. All rights reserved.
|
||
|
|
// Use of this source code is governed by a BSD-style
|
||
|
|
// license that can be found in the LICENSE file.
|
||
|
|
|
||
|
|
package bigmod
|
||
|
|
|
||
|
|
// The generic implementation relies on 64x64->128 bit multiplication and
|
||
|
|
// 64-bit add-with-carry, which are compiler intrinsics on many architectures.
|
||
|
|
// Wasm doesn't support those. Here we implement it with 32x32->64 bit
|
||
|
|
// operations, which is more efficient on Wasm.
|
||
|
|
|
||
|
|
// addMulVVW multiplies the multi-word value x by the single-word value y,
|
||
|
|
// adding the result to the multi-word value z and returning the final carry.
|
||
|
|
// It can be thought of as one row of a pen-and-paper column multiplication.
|
||
|
|
func addMulVVW(z, x []uint, y uint) (carry uint) {
|
||
|
|
const mask32 = 1<<32 - 1
|
||
|
|
y0 := y & mask32
|
||
|
|
y1 := y >> 32
|
||
|
|
_ = x[len(z)-1] // bounds check elimination hint
|
||
|
|
for i, zi := range z {
|
||
|
|
xi := x[i]
|
||
|
|
x0 := xi & mask32
|
||
|
|
x1 := xi >> 32
|
||
|
|
z0 := zi & mask32
|
||
|
|
z1 := zi >> 32
|
||
|
|
c0 := carry & mask32
|
||
|
|
c1 := carry >> 32
|
||
|
|
|
||
|
|
w00 := x0*y0 + z0 + c0
|
||
|
|
l00 := w00 & mask32
|
||
|
|
h00 := w00 >> 32
|
||
|
|
|
||
|
|
w01 := x0*y1 + z1 + h00
|
||
|
|
l01 := w01 & mask32
|
||
|
|
h01 := w01 >> 32
|
||
|
|
|
||
|
|
w10 := x1*y0 + c1 + l01
|
||
|
|
h10 := w10 >> 32
|
||
|
|
|
||
|
|
carry = x1*y1 + h10 + h01
|
||
|
|
z[i] = w10<<32 + l00
|
||
|
|
}
|
||
|
|
return carry
|
||
|
|
}
|