Help us shape the future of Go! Take the 2026 Go Developer Survey

Source file src/simd/internal/spec/variation.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  package spec
     6  
     7  import (
     8  	"fmt"
     9  	"math"
    10  	"strings"
    11  )
    12  
    13  // Platform identifies a specific platform (generally a GOARCH) for
    14  // platform-defined behavior.
    15  type Platform int8
    16  
    17  const (
    18  	PlatformAMD64 Platform = iota
    19  	PlatformARM64
    20  	PlatformWASM
    21  
    22  	numPlatforms
    23  
    24  	// PlatformAny permits the behavior of any platform (for example, when
    25  	// testing the portable simd package or emulated execution).
    26  	PlatformAny Platform = -1
    27  )
    28  
    29  func (p Platform) String() string {
    30  	switch p {
    31  	case PlatformAMD64:
    32  		return "amd64"
    33  	case PlatformARM64:
    34  		return "arm64"
    35  	case PlatformWASM:
    36  		return "wasm"
    37  	case PlatformAny:
    38  		return "any"
    39  	}
    40  	return fmt.Sprintf("Platform(%d)", p)
    41  }
    42  
    43  // Variation represents a value of type E that may vary between platforms.
    44  //
    45  // Its zero value is the exact zero value of E.
    46  //
    47  // This type is known to specgen.
    48  type Variation[E EltOrMask] struct {
    49  	canon E
    50  	v     variation[E] // nil means exact match on canon
    51  }
    52  
    53  type variation[E EltOrMask] interface {
    54  	permits(x E, plat Platform) bool
    55  	String() string
    56  }
    57  
    58  func (Variation[E]) elemBits() int {
    59  	return elemBits[E]()
    60  }
    61  
    62  // Permits reports whether this variation permits value x on plat.
    63  func (v Variation[E]) Permits(x E, plat Platform) bool {
    64  	if v.v == nil {
    65  		return equalExact(x, v.canon)
    66  	}
    67  	return v.v.permits(x, plat)
    68  }
    69  
    70  // Canon returns a single canonical value for this variation.
    71  func (v Variation[E]) Canon() E {
    72  	return v.canon
    73  }
    74  
    75  // String returns this variation as a human-readable string.
    76  func (v Variation[E]) String() string {
    77  	if v.v == nil {
    78  		return fmt.Sprint(v.canon)
    79  	}
    80  	return v.v.String()
    81  }
    82  
    83  // exact returns a [Variation] that permits only x.
    84  func exact[E EltOrMask](x E) Variation[E] {
    85  	return Variation[E]{canon: x}
    86  }
    87  
    88  // perPlatform returns a [Variation] with a specific, but different value per
    89  // platform. The canonical value is the value for the smallest present Platform
    90  // value.
    91  func perPlatform[E EltOrMask](vals map[Platform]E) Variation[E] {
    92  	if len(vals) == 0 {
    93  		panic("perPlatform requires at least one platform value")
    94  	}
    95  	var pp perPlatformVar[E]
    96  	var canon E
    97  	haveCanon := false
    98  	for p := range numPlatforms {
    99  		if val, ok := vals[p]; ok {
   100  			pp.values[p] = val
   101  			pp.present |= 1 << p
   102  			if !haveCanon {
   103  				canon = val
   104  				haveCanon = true
   105  			}
   106  		}
   107  	}
   108  	if pp.present == 0 {
   109  		panic("perPlatform contains no recognized platforms")
   110  	}
   111  	return Variation[E]{canon: canon, v: pp}
   112  }
   113  
   114  // perPlatformDefault is like [perPlatform], but every platform not in vals
   115  // gets value def. Unlike perPlatform, this extends to platforms added in the
   116  // future, so use it only when def is known to be right for any reasonable
   117  // platform.
   118  func perPlatformDefault[E EltOrMask](def E, vals map[Platform]E) Variation[E] {
   119  	all := make(map[Platform]E, numPlatforms)
   120  	for p := range numPlatforms {
   121  		all[p] = def
   122  	}
   123  	for p, val := range vals {
   124  		all[p] = val
   125  	}
   126  	return perPlatform(all)
   127  }
   128  
   129  type perPlatformVar[E EltOrMask] struct {
   130  	values  [numPlatforms]E
   131  	present uint8 // Bit mask over 1<<Platform
   132  }
   133  
   134  func (pp perPlatformVar[E]) permits(x E, plat Platform) bool {
   135  	if plat == PlatformAny {
   136  		for p := range numPlatforms {
   137  			if pp.present&(1<<p) != 0 && equalExact(x, pp.values[p]) {
   138  				return true
   139  			}
   140  		}
   141  		return false
   142  	}
   143  	if plat < 0 || plat >= numPlatforms || pp.present&(1<<plat) == 0 {
   144  		return false
   145  	}
   146  	return equalExact(x, pp.values[plat])
   147  }
   148  
   149  func (pp perPlatformVar[E]) String() string {
   150  	var b strings.Builder
   151  	b.WriteByte('{')
   152  	for p := range numPlatforms {
   153  		if pp.present&(1<<p) != 0 {
   154  			if b.Len() > 1 {
   155  				b.WriteByte(' ')
   156  			}
   157  			fmt.Fprintf(&b, "%s:%v", p, pp.values[p])
   158  		}
   159  	}
   160  	b.WriteByte('}')
   161  	return b.String()
   162  }
   163  
   164  // ulps returns a [Variation] that permits any value within n ULPs of x.
   165  func ulps[E Floats](x E, n uint64) Variation[E] {
   166  	if n == 0 {
   167  		return exact(x)
   168  	}
   169  	return Variation[E]{canon: x, v: ulpsVar[E]{x: x, ulps: n}}
   170  }
   171  
   172  type ulpsVar[E Floats] struct {
   173  	x    E
   174  	ulps uint64
   175  }
   176  
   177  func (u ulpsVar[E]) permits(got E, _ Platform) bool {
   178  	if equalExact(got, u.x) {
   179  		return true
   180  	}
   181  	// Require NaN and +/-inf to match exactly, and require the same sign.
   182  	got64, want64 := float64(got), float64(u.x) // Preserves NaN, +/-inf, and sign
   183  	if math.IsNaN(got64) || math.IsNaN(want64) ||
   184  		math.IsInf(got64, 0) || math.IsInf(want64, 0) ||
   185  		math.Signbit(got64) != math.Signbit(want64) {
   186  		return false
   187  	}
   188  	// By design, IEEE 754 binary representations of finite floats with the same
   189  	// sign bit are ordered monotonically by magnitude, with adjacent representable
   190  	// values differing by 1 (including across subnormals and the subnormal/normal
   191  	// boundary). Thus, the ULP distance is simply the difference between their
   192  	// integer bit patterns.
   193  	switch want := any(u.x).(type) {
   194  	case float32:
   195  		gb, wb := math.Float32bits(any(got).(float32)), math.Float32bits(want)
   196  		return uint64(max(gb, wb)-min(gb, wb)) <= u.ulps
   197  	case float64:
   198  		gb, wb := math.Float64bits(any(got).(float64)), math.Float64bits(want)
   199  		return max(gb, wb)-min(gb, wb) <= u.ulps
   200  	}
   201  	panic("unreachable")
   202  }
   203  
   204  func (u ulpsVar[E]) String() string {
   205  	return fmt.Sprintf("%v±%dulp", u.x, u.ulps)
   206  }
   207  
   208  // anyOf returns a [Variation] that permits any of the values in vals.
   209  // Value 0 is the canonical value.
   210  //
   211  // Prefer [perPlatform].
   212  func anyOf[E EltOrMask](vals ...E) Variation[E] {
   213  	if len(vals) == 0 {
   214  		panic("anyOf requires at least one value")
   215  	}
   216  	if len(vals) == 1 {
   217  		return exact(vals[0])
   218  	}
   219  	return Variation[E]{canon: vals[0], v: anyOfVar[E](vals)}
   220  }
   221  
   222  type anyOfVar[E EltOrMask] []E
   223  
   224  func (a anyOfVar[E]) permits(x E, _ Platform) bool {
   225  	for _, v := range a {
   226  		if equalExact(x, v) {
   227  			return true
   228  		}
   229  	}
   230  	return false
   231  }
   232  
   233  func (a anyOfVar[E]) String() string {
   234  	var b strings.Builder
   235  	b.WriteByte('{')
   236  	for i, v := range a {
   237  		if i > 0 {
   238  			b.WriteByte('|')
   239  		}
   240  		fmt.Fprint(&b, v)
   241  	}
   242  	b.WriteByte('}')
   243  	return b.String()
   244  }
   245  
   246  // undef returns a [Variation] that is fully undefined and permits any value.
   247  // The canonical value is the zero value of E.
   248  //
   249  // Try really hard not to use this. Even undefined results should be
   250  // deterministic on a given platform, and it's better to model that as
   251  // [perPlatform], or [anyOf].
   252  func undef[E EltOrMask]() Variation[E] {
   253  	return Variation[E]{v: undefVar[E]{}}
   254  }
   255  
   256  type undefVar[E EltOrMask] struct{}
   257  
   258  func (undefVar[E]) permits(_ E, _ Platform) bool { return true }
   259  func (undefVar[E]) String() string               { return "undef" }
   260  
   261  // equalExact reports whether got and want are bitwise identical, except that
   262  // all NaN bit patterns are considered equal to each other.
   263  func equalExact[E EltOrMask](got, want E) bool {
   264  	switch got := any(got).(type) {
   265  	case float32:
   266  		want := any(want).(float32)
   267  		if math.IsNaN(float64(got)) && math.IsNaN(float64(want)) {
   268  			return true
   269  		}
   270  		return math.Float32bits(got) == math.Float32bits(want)
   271  	case float64:
   272  		want := any(want).(float64)
   273  		if math.IsNaN(got) && math.IsNaN(want) {
   274  			return true
   275  		}
   276  		return math.Float64bits(got) == math.Float64bits(want)
   277  	}
   278  	return got == want
   279  }
   280  

View as plain text