// Copyright 2025 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 asmgen // addOrSubVV generates addVV or subVV, // which do z, c = x ± y. // The caller guarantees that len(z) == len(x) == len(y). func addOrSubVV(a *Asm, name string) { f := a.Func("func " + name + "(z, x, y []Word) (c Word)") add := a.Add which := AddCarry if name == "subVV" { add = a.Sub which = SubCarry } n := f.Arg("z_len") p := f.Pipe() p.SetHint("y", HintMemOK) // allow y to be used from memory on x86 p.Start(n, 1, 4) var c Reg if !a.Arch.CarrySafeLoop { // Carry smashed by loop tests; allocate and save in register // around unrolled blocks. c = a.Reg() a.Mov(a.Imm(0), c) a.EOL("clear saved carry") p.AtUnrollStart(func() { a.RestoreCarry(c); a.Free(c) }) p.AtUnrollEnd(func() { a.Unfree(c); a.SaveCarry(c) }) } else { // Carry preserved by loop; clear now, ahead of loop // (but after Start, which may have modified it). a.ClearCarry(which) } p.Loop(func(in, out [][]Reg) { for i, x := range in[0] { y := in[1][i] add(y, x, x, SetCarry|UseCarry) } p.StoreN(in[:1]) }) p.Done() // Copy carry to output. if c.Valid() { a.ConvertCarry(which, c) } else { c = a.RegHint(HintCarry) a.SaveConvertCarry(which, c) } f.StoreArg(c, "c") a.Free(c) a.Ret() }