add.mx raw

   1  // Copyright 2025 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  package asmgen
   6  
   7  // addOrSubVV generates addVV or subVV,
   8  // which do z, c = x ± y.
   9  // The caller guarantees that len(z) == len(x) == len(y).
  10  func addOrSubVV(a *Asm, name []byte) {
  11  	f := a.Func("func " + name + "(z, x, y []Word) (c Word)")
  12  
  13  	add := a.Add
  14  	which := AddCarry
  15  	if name == "subVV" {
  16  		add = a.Sub
  17  		which = SubCarry
  18  	}
  19  
  20  	n := f.Arg("z_len")
  21  	p := f.Pipe()
  22  	p.SetHint("y", HintMemOK) // allow y to be used from memory on x86
  23  	p.Start(n, 1, 4)
  24  	var c Reg
  25  	if !a.Arch.CarrySafeLoop {
  26  		// Carry smashed by loop tests; allocate and save in register
  27  		// around unrolled blocks.
  28  		c = a.Reg()
  29  		a.Mov(a.Imm(0), c)
  30  		a.EOL("clear saved carry")
  31  		p.AtUnrollStart(func() { a.RestoreCarry(c); a.Free(c) })
  32  		p.AtUnrollEnd(func() { a.Unfree(c); a.SaveCarry(c) })
  33  	} else {
  34  		// Carry preserved by loop; clear now, ahead of loop
  35  		// (but after Start, which may have modified it).
  36  		a.ClearCarry(which)
  37  	}
  38  	p.Loop(func(in, out [][]Reg) {
  39  		for i, x := range in[0] {
  40  			y := in[1][i]
  41  			add(y, x, x, SetCarry|UseCarry)
  42  		}
  43  		p.StoreN(in[:1])
  44  	})
  45  	p.Done()
  46  
  47  	// Copy carry to output.
  48  	if c.Valid() {
  49  		a.ConvertCarry(which, c)
  50  	} else {
  51  		c = a.RegHint(HintCarry)
  52  		a.SaveConvertCarry(which, c)
  53  	}
  54  	f.StoreArg(c, "c")
  55  	a.Free(c)
  56  	a.Ret()
  57  }
  58