summaryrefslogtreecommitdiff
path: root/vendor/github.com/tetratelabs/wazero/internal/platform/cpuid_amd64.go
blob: fbdb539366186880b7eef7708c2b11ca5c11c094 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
//go:build amd64 && !tinygo

package platform

// CpuFeatures exposes the capabilities for this CPU, queried via the Has, HasExtra methods.
var CpuFeatures = loadCpuFeatureFlags()

// cpuFeatureFlags implements CpuFeatureFlags interface.
type cpuFeatureFlags struct {
	flags      uint64
	extraFlags uint64
}

// cpuid exposes the CPUID instruction to the Go layer (https://www.amd.com/system/files/TechDocs/25481.pdf)
// implemented in impl_amd64.s
func cpuid(arg1, arg2 uint32) (eax, ebx, ecx, edx uint32)

// cpuidAsBitmap combines the result of invoking cpuid to uint64 bitmap.
func cpuidAsBitmap(arg1, arg2 uint32) uint64 {
	_ /* eax */, _ /* ebx */, ecx, edx := cpuid(arg1, arg2)
	return (uint64(edx) << 32) | uint64(ecx)
}

// loadStandardRange load flags from the standard range, panics otherwise.
func loadStandardRange(id uint32) uint64 {
	// ensure that the id is in the valid range, returned by cpuid(0,0)
	maxRange, _, _, _ := cpuid(0, 0)
	if id > maxRange {
		panic("cannot query standard CPU flags")
	}
	return cpuidAsBitmap(id, 0)
}

// loadStandardRange load flags from the extended range, panics otherwise.
func loadExtendedRange(id uint32) uint64 {
	// ensure that the id is in the valid range, returned by cpuid(0x80000000,0)
	maxRange, _, _, _ := cpuid(0x80000000, 0)
	if id > maxRange {
		panic("cannot query extended CPU flags")
	}
	return cpuidAsBitmap(id, 0)
}

func loadCpuFeatureFlags() CpuFeatureFlags {
	return &cpuFeatureFlags{
		flags:      loadStandardRange(1),
		extraFlags: loadExtendedRange(0x80000001),
	}
}

// Has implements the same method on the CpuFeatureFlags interface.
func (f *cpuFeatureFlags) Has(cpuFeature CpuFeature) bool {
	return (f.flags & uint64(cpuFeature)) != 0
}

// HasExtra implements the same method on the CpuFeatureFlags interface.
func (f *cpuFeatureFlags) HasExtra(cpuFeature CpuFeature) bool {
	return (f.extraFlags & uint64(cpuFeature)) != 0
}

// Raw implements the same method on the CpuFeatureFlags interface.
func (f *cpuFeatureFlags) Raw() uint64 {
	// Below, we only set the first 4 bits for the features we care about,
	// instead of setting all the unnecessary bits obtained from the CPUID instruction.
	var ret uint64
	if f.Has(CpuFeatureAmd64SSE3) {
		ret = 1 << 0
	}
	if f.Has(CpuFeatureAmd64SSE4_1) {
		ret |= 1 << 1
	}
	if f.Has(CpuFeatureAmd64SSE4_2) {
		ret |= 1 << 2
	}
	if f.HasExtra(CpuExtraFeatureAmd64ABM) {
		ret |= 1 << 3
	}
	return ret
}