Source file src/vendor/golang.org/x/sys/cpu/cpu_darwin_x86.go

     1  // Copyright 2024 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  //go:build darwin && amd64 && gc
     6  
     7  package cpu
     8  
     9  // darwinSupportsAVX512 checks Darwin kernel for AVX512 support via sysctl
    10  // call (see issue 43089). It also restricts AVX512 support for Darwin to
    11  // kernel version 21.3.0 (MacOS 12.2.0) or later (see issue 49233).
    12  //
    13  // Background:
    14  // Darwin implements a special mechanism to economize on thread state when
    15  // AVX512 specific registers are not in use. This scheme minimizes state when
    16  // preempting threads that haven't yet used any AVX512 instructions, but adds
    17  // special requirements to check for AVX512 hardware support at runtime (e.g.
    18  // via sysctl call or commpage inspection). See issue 43089 and link below for
    19  // full background:
    20  // https://github.com/apple-oss-distributions/xnu/blob/xnu-11215.1.10/osfmk/i386/fpu.c#L214-L240
    21  //
    22  // Additionally, all versions of the Darwin kernel from 19.6.0 through 21.2.0
    23  // (corresponding to MacOS 10.15.6 - 12.1) have a bug that can cause corruption
    24  // of the AVX512 mask registers (K0-K7) upon signal return. For this reason
    25  // AVX512 is considered unsafe to use on Darwin for kernel versions prior to
    26  // 21.3.0, where a fix has been confirmed. See issue 49233 for full background.
    27  func darwinSupportsAVX512() bool {
    28  	return darwinSysctlEnabled([]byte("hw.optional.avx512f\x00")) && darwinKernelVersionCheck(21, 3, 0)
    29  }
    30  
    31  // Ensure Darwin kernel version is at least major.minor.patch, avoiding dependencies
    32  func darwinKernelVersionCheck(major, minor, patch int) bool {
    33  	var release [256]byte
    34  	err := darwinOSRelease(&release)
    35  	if err != nil {
    36  		return false
    37  	}
    38  
    39  	var mmp [3]int
    40  	c := 0
    41  Loop:
    42  	for _, b := range release[:] {
    43  		switch {
    44  		case b >= '0' && b <= '9':
    45  			mmp[c] = 10*mmp[c] + int(b-'0')
    46  		case b == '.':
    47  			c++
    48  			if c > 2 {
    49  				return false
    50  			}
    51  		case b == 0:
    52  			break Loop
    53  		default:
    54  			return false
    55  		}
    56  	}
    57  	if c != 2 {
    58  		return false
    59  	}
    60  	return mmp[0] > major || mmp[0] == major && (mmp[1] > minor || mmp[1] == minor && mmp[2] >= patch)
    61  }
    62  

View as plain text