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