cpu: add amd64 v2/v3/v4 feature bits

Updates https://go.dev/issues/58015 (this adds the underlying feature bits necessary for that consistent with what this repository already implements, but doesn't add an explicit "level")

Change-ID: I87a36c669bbb151df7c49e98fdadc808ed0db820
Assisted-By: "claude my eyes right out"
Reviewed-on: https://go-review.googlesource.com/c/sys/+/822061
Auto-Submit: Tobias Klauser <tobias.klauser@gmail.com>
Reviewed-by: Cherry Mui <cherryyz@google.com>
LUCI-TryBot-Result: golang-scoped@luci-project-accounts.iam.gserviceaccount.com <golang-scoped@luci-project-accounts.iam.gserviceaccount.com>
Reviewed-by: Tianon Gravi <admwiggin@gmail.com>
Reviewed-by: Tobias Klauser <tobias.klauser@gmail.com>
Reviewed-by: Samuel Karp <samuelkarp@google.com>
diff --git a/cpu/cpu.go b/cpu/cpu.go
index df8dbd1..422b139 100644
--- a/cpu/cpu.go
+++ b/cpu/cpu.go
@@ -61,7 +61,11 @@
 	HasBMI2             bool // Bit manipulation instruction set 2
 	HasCX16             bool // Compare and exchange 16 Bytes
 	HasERMS             bool // Enhanced REP for MOVSB and STOSB
+	HasF16C             bool // 16-bit floating-point conversion instructions
 	HasFMA              bool // Fused-multiply-add instructions
+	HasLAHF             bool // LAHF/SAHF available in 64-bit mode
+	HasLZCNT            bool // Leading zeros count instruction
+	HasMOVBE            bool // Move data after byte swap
 	HasOSXSAVE          bool // OS supports XSAVE/XRESTOR for saving/restoring XMM registers.
 	HasPCLMULQDQ        bool // PCLMULQDQ instruction - most often used for AES-GCM
 	HasPOPCNT           bool // Hamming weight instruction POPCNT.
@@ -75,6 +79,7 @@
 	HasAVXIFMA          bool // Advanced vector extension Integer Fused Multiply Add
 	HasAVXVNNI          bool // Advanced vector extension Vector Neural Network Instructions
 	HasAVXVNNIInt8      bool // Advanced vector extension Vector Neural Network Int8 instructions
+	HasXSAVE            bool // XSAVE/XRSTOR/XSETBV/XGETBV instructions (hardware support; see also HasOSXSAVE)
 	_                   CacheLinePad
 }
 
diff --git a/cpu/cpu_x86.go b/cpu/cpu_x86.go
index f5723d4..7e6cead 100644
--- a/cpu/cpu_x86.go
+++ b/cpu/cpu_x86.go
@@ -43,7 +43,11 @@
 		{Name: "bmi2", Feature: &X86.HasBMI2},
 		{Name: "cx16", Feature: &X86.HasCX16},
 		{Name: "erms", Feature: &X86.HasERMS},
+		{Name: "f16c", Feature: &X86.HasF16C},
 		{Name: "fma", Feature: &X86.HasFMA},
+		{Name: "lahf", Feature: &X86.HasLAHF},
+		{Name: "lzcnt", Feature: &X86.HasLZCNT},
+		{Name: "movbe", Feature: &X86.HasMOVBE},
 		{Name: "osxsave", Feature: &X86.HasOSXSAVE},
 		{Name: "pclmulqdq", Feature: &X86.HasPCLMULQDQ},
 		{Name: "popcnt", Feature: &X86.HasPOPCNT},
@@ -56,6 +60,7 @@
 		{Name: "avxifma", Feature: &X86.HasAVXIFMA},
 		{Name: "avxvnni", Feature: &X86.HasAVXVNNI},
 		{Name: "avxvnniint8", Feature: &X86.HasAVXVNNIInt8},
+		{Name: "xsave", Feature: &X86.HasXSAVE},
 
 		// These capabilities should always be enabled on amd64:
 		{Name: "sse2", Feature: &X86.HasSSE2, Required: runtime.GOARCH == "amd64"},
@@ -83,10 +88,13 @@
 		cpuid_AVX512VPOPCNTDQ = 1 << 14
 		cpuid_SSE41           = 1 << 19
 		cpuid_SSE42           = 1 << 20
+		cpuid_MOVBE           = 1 << 22
 		cpuid_POPCNT          = 1 << 23
 		cpuid_AES             = 1 << 25
+		cpuid_XSAVE           = 1 << 26
 		cpuid_OSXSAVE         = 1 << 27
 		cpuid_AVX             = 1 << 28
+		cpuid_F16C            = 1 << 29
 
 		// "Extended Feature Flag" bits returned in EBX for CPUID EAX=0x7 ECX=0x0
 		cpuid_BMI1     = 1 << 3
@@ -110,6 +118,9 @@
 
 		// edx bits
 		cpuid_FSRM = 1 << 4
+		// ecx bits for CPUID 0x80000001
+		cpuid_LAHF  = 1 << 0
+		cpuid_LZCNT = 1 << 5
 		// edx bits for CPUID 0x80000001
 		cpuid_RDTSCP = 1 << 27
 	)
@@ -158,9 +169,21 @@
 	X86.HasSSE42 = isSet(ecx1, cpuid_SSE42)
 	X86.HasPOPCNT = isSet(ecx1, cpuid_POPCNT)
 	X86.HasAES = isSet(ecx1, cpuid_AES)
+	X86.HasXSAVE = isSet(ecx1, cpuid_XSAVE)
 	X86.HasOSXSAVE = isSet(ecx1, cpuid_OSXSAVE)
+	X86.HasF16C = isSet(ecx1, cpuid_F16C)
+	X86.HasMOVBE = isSet(ecx1, cpuid_MOVBE)
 	X86.HasRDRAND = isSet(ecx1, cpuid_RDRAND)
 
+	// Extended processor info and feature bits, under the separate extended
+	// (0x8000_0000-prefixed) leaf hierarchy, so maxID (the basic leaf count)
+	// doesn't gate it.
+	if maxExtID, _, _, _ := cpuid(0x80000000, 0); maxExtID >= 0x80000001 {
+		_, _, ecxExt1, _ := cpuid(0x80000001, 0)
+		X86.HasLAHF = isSet(ecxExt1, cpuid_LAHF)
+		X86.HasLZCNT = isSet(ecxExt1, cpuid_LZCNT)
+	}
+
 	var osSupportsAVX, osSupportsAVX512 bool
 	// For XGETBV, OSXSAVE bit is required and sufficient.
 	if X86.HasOSXSAVE {