Source file src/simd/internal/spec/math-concat.go

     1  // Copyright 2026 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  //specgen:category Math (concatenated)
     6  
     7  package spec
     8  
     9  // ConcatAddPairs horizontally adds adjacent pairs of elements in x and y and
    10  // returns the concatenated result.
    11  //
    12  // {{if eq .xL 2}}
    13  //
    14  //	z = {x[0]+x[1], y[0]+y[1]}
    15  //
    16  // {{else if eq .xL 4}}
    17  //
    18  //	z = {x[0]+x[1], x[2]+x[3], y[0]+y[1], y[2]+y[3]}
    19  //
    20  // {{else}}
    21  //
    22  //	z = {x[0]+x[1], x[2]+x[3], ..., y[0]+y[1], y[2]+y[3], ...}
    23  //
    24  // {{end}}
    25  func ConcatAddPairs[E Nums, W Width](x, y Vec[E, W]) (z Vec[E, W]) {
    26  	z = makeVec[E, W]()
    27  	half := z.len() / 2
    28  	for i := 0; i < half; i++ {
    29  		z[i] = x[2*i] + x[2*i+1]
    30  		z[half+i] = y[2*i] + y[2*i+1]
    31  	}
    32  	return z
    33  }
    34  
    35  // ConcatSubPairs horizontally subtracts adjacent pairs of elements in x and y
    36  // and returns the concatenated result.
    37  //
    38  // {{if eq .xL 2}}
    39  //
    40  //	z = {x[0]-x[1], y[0]-y[1]}
    41  //
    42  // {{else if eq .xL 4}}
    43  //
    44  //	z = {x[0]-x[1], x[2]-x[3], y[0]-y[1], y[2]-y[3]}
    45  //
    46  // {{else}}
    47  //
    48  //	z = {x[0]-x[1], x[2]-x[3], ..., y[0]-y[1], y[2]-y[3], ...}
    49  //
    50  // {{end}}
    51  func ConcatSubPairs[E Nums, W Width](x, y Vec[E, W]) (z Vec[E, W]) {
    52  	z = makeVec[E, W]()
    53  	half := z.len() / 2
    54  	for i := 0; i < half; i++ {
    55  		z[i] = x[2*i] - x[2*i+1]
    56  		z[half+i] = y[2*i] - y[2*i+1]
    57  	}
    58  	return z
    59  }
    60  
    61  // ConcatMaxPairs horizontally takes the maximum of adjacent pairs of elements
    62  // in x and y and returns the concatenated result.
    63  //
    64  // {{if eq .xL 2}}
    65  //
    66  //	z = {max(x[0], x[1]), max(y[0], y[1])}
    67  //
    68  // {{else if eq .xL 4}}
    69  //
    70  //	z = {max(x[0], x[1]), max(x[2], x[3]), max(y[0], y[1]), max(y[2], y[3])}
    71  //
    72  // {{else}}
    73  //
    74  //	z = {max(x[0], x[1]), max(x[2], x[3]), ..., max(y[0], y[1]), max(y[2], y[3]), ...}
    75  //
    76  // {{end}}
    77  //
    78  // For floats, max is Go's max built-in: it returns NaN if either element is
    79  // NaN, and orders -0 before +0.
    80  func ConcatMaxPairs[E Nums, W Width](x, y Vec[E, W]) (z Vec[E, W]) {
    81  	// Only ARM64 implements this (FMAXP, SMAXP, UMAXP), and its float form
    82  	// follows IEEE 754-2019 maximum like Go's max. If another platform
    83  	// implements it with its own Max, see MaxFloats about AMD64.
    84  	z = makeVec[E, W]()
    85  	half := z.len() / 2
    86  	for i := 0; i < half; i++ {
    87  		z[i] = max(x[2*i], x[2*i+1])
    88  		z[half+i] = max(y[2*i], y[2*i+1])
    89  	}
    90  	return z
    91  }
    92  
    93  // ConcatMinPairs horizontally takes the minimum of adjacent pairs of elements
    94  // in x and y and returns the concatenated result.
    95  //
    96  // {{if eq .xL 2}}
    97  //
    98  //	z = {min(x[0], x[1]), min(y[0], y[1])}
    99  //
   100  // {{else if eq .xL 4}}
   101  //
   102  //	z = {min(x[0], x[1]), min(x[2], x[3]), min(y[0], y[1]), min(y[2], y[3])}
   103  //
   104  // {{else}}
   105  //
   106  //	z = {min(x[0], x[1]), min(x[2], x[3]), ..., min(y[0], y[1]), min(y[2], y[3]), ...}
   107  //
   108  // {{end}}
   109  //
   110  // For floats, min is Go's min built-in: it returns NaN if either element is
   111  // NaN, and orders -0 before +0.
   112  func ConcatMinPairs[E Nums, W Width](x, y Vec[E, W]) (z Vec[E, W]) {
   113  	// See ConcatMaxPairs about platforms.
   114  	z = makeVec[E, W]()
   115  	half := z.len() / 2
   116  	for i := 0; i < half; i++ {
   117  		z[i] = min(x[2*i], x[2*i+1])
   118  		z[half+i] = min(y[2*i], y[2*i+1])
   119  	}
   120  	return z
   121  }
   122  
   123  // ConcatAddPairsSaturated horizontally adds adjacent pairs of elements in x and
   124  // y with saturation and returns the concatenated result.
   125  //
   126  // {{if eq .xL 2}}
   127  //
   128  //	z = {sat(x[0]+x[1]), sat(y[0]+y[1])}
   129  //
   130  // {{else if eq .xL 4}}
   131  //
   132  //	z = {sat(x[0]+x[1]), sat(x[2]+x[3]), sat(y[0]+y[1]), sat(y[2]+y[3])}
   133  //
   134  // {{else}}
   135  //
   136  //	z = {sat(x[0]+x[1]), sat(x[2]+x[3]), ..., sat(y[0]+y[1]), sat(y[2]+y[3]), ...}
   137  //
   138  // {{end}}
   139  func ConcatAddPairsSaturated[E Ints | Uints, W Width](x, y Vec[E, W]) (z Vec[E, W]) {
   140  	z = makeVec[E, W]()
   141  	half := z.len() / 2
   142  	for i := 0; i < half; i++ {
   143  		z[i] = addSaturated(x[2*i], x[2*i+1])
   144  		z[half+i] = addSaturated(y[2*i], y[2*i+1])
   145  	}
   146  	return z
   147  }
   148  
   149  // ConcatSubPairsSaturated horizontally subtracts adjacent pairs of elements in
   150  // x and y with saturation and returns the concatenated result.
   151  //
   152  // {{if eq .xL 2}}
   153  //
   154  //	z = {sat(x[0]-x[1]), sat(y[0]-y[1])}
   155  //
   156  // {{else if eq .xL 4}}
   157  //
   158  //	z = {sat(x[0]-x[1]), sat(x[2]-x[3]), sat(y[0]-y[1]), sat(y[2]-y[3])}
   159  //
   160  // {{else}}
   161  //
   162  //	z = {sat(x[0]-x[1]), sat(x[2]-x[3]), ..., sat(y[0]-y[1]), sat(y[2]-y[3]), ...}
   163  //
   164  // {{end}}
   165  func ConcatSubPairsSaturated[E Ints | Uints, W Width](x, y Vec[E, W]) (z Vec[E, W]) {
   166  	z = makeVec[E, W]()
   167  	half := z.len() / 2
   168  	for i := 0; i < half; i++ {
   169  		z[i] = subSaturated(x[2*i], x[2*i+1])
   170  		z[half+i] = subSaturated(y[2*i], y[2*i+1])
   171  	}
   172  	return z
   173  }
   174  
   175  // ConcatAddPairsGrouped divides x, y, and z into groups of 128 bits and
   176  // performs [ConcatAddPairs] on each group.
   177  func ConcatAddPairsGrouped[E Nums, W Width](x, y Vec[E, W]) (z Vec[E, W]) {
   178  	return grouped128(ConcatAddPairs, x, y)
   179  }
   180  
   181  // ConcatSubPairsGrouped divides x, y, and z into groups of 128 bits and
   182  // performs [ConcatSubPairs] on each group.
   183  func ConcatSubPairsGrouped[E Nums, W Width](x, y Vec[E, W]) (z Vec[E, W]) {
   184  	return grouped128(ConcatSubPairs, x, y)
   185  }
   186  
   187  // ConcatAddPairsSaturatedGrouped divides x, y, and z into groups of 128 bits
   188  // and performs [ConcatAddPairsSaturated] on each group.
   189  func ConcatAddPairsSaturatedGrouped[E Ints | Uints, W Width](x, y Vec[E, W]) (z Vec[E, W]) {
   190  	return grouped128(ConcatAddPairsSaturated, x, y)
   191  }
   192  
   193  // ConcatSubPairsSaturatedGrouped divides x, y, and z into groups of 128 bits
   194  // and performs [ConcatSubPairsSaturated] on each group.
   195  func ConcatSubPairsSaturatedGrouped[E Ints | Uints, W Width](x, y Vec[E, W]) (z Vec[E, W]) {
   196  	return grouped128(ConcatSubPairsSaturated, x, y)
   197  }
   198  

View as plain text