nat_wasm.mx raw

   1  // Copyright 2024 The Go Authors. All rights reserved.
   2  // Use of this source code is governed by a BSD-style
   3  // license that can be found in the LICENSE file.
   4  
   5  //go:build !purego
   6  
   7  package bigmod
   8  
   9  import "unsafe"
  10  
  11  // The generic implementation relies on 64x64->128 bit multiplication and
  12  // 64-bit add-with-carry, which are compiler intrinsics on many architectures.
  13  // Wasm doesn't support those. Here we implement it with 32x32->64 bit
  14  // operations, which is more efficient on Wasm.
  15  
  16  func idx(x *uint, i uintptr) *uint {
  17  	return (*uint)(unsafe.Pointer(uintptr(unsafe.Pointer(x)) + i*8))
  18  }
  19  
  20  func addMulVVWWasm(z, x *uint, y uint, n uintptr) (carry uint) {
  21  	const mask32 = 1<<32 - 1
  22  	y0 := y & mask32
  23  	y1 := y >> 32
  24  	for i := range n {
  25  		xi := *idx(x, i)
  26  		x0 := xi & mask32
  27  		x1 := xi >> 32
  28  		zi := *idx(z, i)
  29  		z0 := zi & mask32
  30  		z1 := zi >> 32
  31  		c0 := carry & mask32
  32  		c1 := carry >> 32
  33  
  34  		w00 := x0*y0 + z0 + c0
  35  		l00 := w00 & mask32
  36  		h00 := w00 >> 32
  37  
  38  		w01 := x0*y1 + z1 + h00
  39  		l01 := w01 & mask32
  40  		h01 := w01 >> 32
  41  
  42  		w10 := x1*y0 + c1 + l01
  43  		h10 := w10 >> 32
  44  
  45  		carry = x1*y1 + h10 + h01
  46  		*idx(z, i) = w10<<32 + l00
  47  	}
  48  	return carry
  49  }
  50  
  51  func addMulVVW1024(z, x *uint, y uint) (c uint) {
  52  	return addMulVVWWasm(z, x, y, 1024/_W)
  53  }
  54  
  55  func addMulVVW1536(z, x *uint, y uint) (c uint) {
  56  	return addMulVVWWasm(z, x, y, 1536/_W)
  57  }
  58  
  59  func addMulVVW2048(z, x *uint, y uint) (c uint) {
  60  	return addMulVVWWasm(z, x, y, 2048/_W)
  61  }
  62