// 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( *Asm,  string) {
	 := .Func("func " +  + "(z, x, y []Word) (c Word)")

	 := .Add
	 := AddCarry
	if  == "subVV" {
		 = .Sub
		 = SubCarry
	}

	 := .Arg("z_len")
	 := .Pipe()
	.SetHint("y", HintMemOK) // allow y to be used from memory on x86
	.Start(, 1, 4)
	var  Reg
	if !.Arch.CarrySafeLoop {
		// Carry smashed by loop tests; allocate and save in register
		// around unrolled blocks.
		 = .Reg()
		.Mov(.Imm(0), )
		.EOL("clear saved carry")
		.AtUnrollStart(func() { .RestoreCarry(); .Free() })
		.AtUnrollEnd(func() { .Unfree(); .SaveCarry() })
	} else {
		// Carry preserved by loop; clear now, ahead of loop
		// (but after Start, which may have modified it).
		.ClearCarry()
	}
	.Loop(func(,  [][]Reg) {
		for ,  := range [0] {
			 := [1][]
			(, , , SetCarry|UseCarry)
		}
		.StoreN([:1])
	})
	.Done()

	// Copy carry to output.
	if .Valid() {
		.ConvertCarry(, )
	} else {
		 = .RegHint(HintCarry)
		.SaveConvertCarry(, )
	}
	.StoreArg(, "c")
	.Free()
	.Ret()
}