aboutsummaryrefslogtreecommitdiff
path: root/core/sys/cpu
diff options
context:
space:
mode:
authorgingerBill <bill@gingerbill.org>2020-11-06 00:39:09 +0000
committergingerBill <bill@gingerbill.org>2020-11-06 00:39:09 +0000
commit7c5247f5fb78263604abb301a67b6bb8a7de2f2a (patch)
tree258fc8edf2c6d68c55c928aa4502f6c4f291dde0 /core/sys/cpu
parent9ac6d45bd6d491c066121725277b5b13f6519339 (diff)
Add package sys/cpu - implements processor feature detection
Diffstat (limited to 'core/sys/cpu')
-rw-r--r--core/sys/cpu/cpu.odin35
-rw-r--r--core/sys/cpu/cpu_x86.odin67
2 files changed, 102 insertions, 0 deletions
diff --git a/core/sys/cpu/cpu.odin b/core/sys/cpu/cpu.odin
new file mode 100644
index 000000000..b6f770aed
--- /dev/null
+++ b/core/sys/cpu/cpu.odin
@@ -0,0 +1,35 @@
+package sys_cpu
+
+#assert(ODIN_USE_LLVM_API);
+
+Cache_Line_Pad :: struct {_: [_cache_line_size]byte};
+
+initialized: bool;
+
+x86: struct {
+ _: Cache_Line_Pad,
+ has_aes: bool, // AES hardware implementation (AES NI)
+ has_adx: bool, // Multi-precision add-carry instruction extensions
+ has_avx: bool, // Advanced vector extension
+ has_avx2: bool, // Advanced vector extension 2
+ has_bmi1: bool, // Bit manipulation instruction set 1
+ has_bmi2: bool, // Bit manipulation instruction set 2
+ has_erms: bool, // Enhanced REP for MOVSB and STOSB
+ has_fma: bool, // Fused-multiply-add instructions
+ has_os_xsave: bool, // OS supports XSAVE/XRESTOR for saving/restoring XMM registers.
+ has_pclmulqdq: bool, // PCLMULQDQ instruction - most often used for AES-GCM
+ has_popcnt: bool, // Hamming weight instruction POPCNT.
+ has_rdrand: bool, // RDRAND instruction (on-chip random number generator)
+ has_rdseed: bool, // RDSEED instruction (on-chip random number generator)
+ has_sse2: bool, // Streaming SIMD extension 2 (always available on amd64)
+ has_sse3: bool, // Streaming SIMD extension 3
+ has_ssse3: bool, // Supplemental streaming SIMD extension 3
+ has_sse41: bool, // Streaming SIMD extension 4 and 4.1
+ has_sse42: bool, // Streaming SIMD extension 4 and 4.2
+ _: Cache_Line_Pad,
+};
+
+
+init :: proc() {
+ _init();
+}
diff --git a/core/sys/cpu/cpu_x86.odin b/core/sys/cpu/cpu_x86.odin
new file mode 100644
index 000000000..8f3560a87
--- /dev/null
+++ b/core/sys/cpu/cpu_x86.odin
@@ -0,0 +1,67 @@
+//+build 386, amd64
+package sys_cpu
+
+_cache_line_size :: 64;
+
+cpuid :: proc(ax, cx: u32) -> (eax, ebc, ecx, edx: u32) {
+ return expand_to_tuple(asm(u32, u32) -> struct{eax, ebc, ecx, edx: u32} {
+ "cpuid",
+ "={ax},={bx},={cx},={dx},{ax},{cx}",
+ }(ax, cx));
+}
+
+xgetbv :: proc() -> (eax, edx: u32) {
+ return expand_to_tuple(asm(u32) -> struct{eax, edx: u32} {
+ "xgetbv",
+ "={ax},={dx},{cx}",
+ }(0));
+}
+
+_init :: proc() {
+ is_set :: proc(hwc: u32, value: u32) -> bool {
+ return hwc&value != 0;
+ }
+
+ initialized = true;
+
+ max_id, _, _, _ := cpuid(0, 0);
+
+ if max_id < 1 {
+ return;
+ }
+
+ _, _, ecx1, edx1 := cpuid(1, 0);
+
+ x86.has_sse2 = is_set(26, edx1);
+
+ x86.has_sse3 = is_set(0, ecx1);
+ x86.has_pclmulqdq = is_set(1, ecx1);
+ x86.has_ssse3 = is_set(9, ecx1);
+ x86.has_fma = is_set(12, ecx1);
+ x86.has_sse41 = is_set(19, ecx1);
+ x86.has_sse42 = is_set(20, ecx1);
+ x86.has_popcnt = is_set(23, ecx1);
+ x86.has_aes = is_set(25, ecx1);
+ x86.has_os_xsave = is_set(27, ecx1);
+ x86.has_rdrand = is_set(30, ecx1);
+
+ os_supports_avx := false;
+ if x86.has_os_xsave {
+ eax, _ := xgetbv();
+ os_supports_avx = is_set(1, eax) && is_set(2, eax);
+ }
+
+ x86.has_avx = is_set(28, ecx1) && os_supports_avx;
+
+ if max_id < 7 {
+ return;
+ }
+
+ _, ebx7, _, _ := cpuid(7, 0);
+ x86.has_bmi1 = is_set(3, ebx7);
+ x86.has_avx2 = is_set(5, ebx7) && os_supports_avx;
+ x86.has_bmi2 = is_set(8, ebx7);
+ x86.has_erms = is_set(9, ebx7);
+ x86.has_rdseed = is_set(18, ebx7);
+ x86.has_adx = is_set(19, ebx7);
+}