Browse Source

Merge branch 'master' of https://github.com/odin-lang/Odin

gingerBill 2 năm trước cách đây
mục cha
commit
3d325e52c6

+ 2 - 2
core/intrinsics/intrinsics.odin

@@ -283,7 +283,7 @@ wasm_memory_atomic_wait32   :: proc(ptr: ^u32, expected: u32, timeout_ns: i64) -
 wasm_memory_atomic_notify32 :: proc(ptr: ^u32, waiters: u32) -> (waiters_woken_up: u32) ---
 
 // x86 Targets (i386, amd64)
-x86_cpuid  :: proc(ax, cx: u32) -> (eax, ebc, ecx, edx: u32) ---
+x86_cpuid  :: proc(ax, cx: u32) -> (eax, ebx, ecx, edx: u32) ---
 x86_xgetbv :: proc(cx: u32) -> (eax, edx: u32) ---
 
 
@@ -305,4 +305,4 @@ valgrind_client_request :: proc(default: uintptr, request: uintptr, a0, a1, a2,
 
 // Internal compiler use only
 
-__entry_point :: proc() ---
+__entry_point :: proc() ---

+ 1 - 1
core/sys/darwin/xnu_system_call_numbers.odin

@@ -1,6 +1,6 @@
 package darwin
 
-unix_offset_syscall :: proc(number: System_Call_Number) -> uintptr {
+unix_offset_syscall :: proc "contextless" (number: System_Call_Number) -> uintptr {
     return uintptr(number) + uintptr(0x2000000)
 }
 

+ 48 - 48
core/sys/darwin/xnu_system_call_wrappers.odin

@@ -229,191 +229,191 @@ _Proc_Bsdinfo :: struct {
 
 /*--==========================================================================--*/
 
-syscall_fsync :: #force_inline proc(fildes: c.int) -> bool {
+syscall_fsync :: #force_inline proc "contextless" (fildes: c.int) -> bool {
 	return !(cast(bool)intrinsics.syscall(unix_offset_syscall(.fsync), uintptr(fildes)))
 }
 
-syscall_write :: #force_inline proc (fildes: c.int, buf: ^byte, nbyte: u64) -> bool {
+syscall_write :: #force_inline proc "contextless" (fildes: c.int, buf: ^byte, nbyte: u64) -> bool {
 	return !(cast(bool)intrinsics.syscall(unix_offset_syscall(.write),  uintptr(fildes), uintptr(buf), uintptr(nbyte)))
 }
  
-syscall_read :: #force_inline proc(fildes: c.int, buf: ^byte, nbyte: u64) -> i64 {
+syscall_read :: #force_inline proc "contextless" (fildes: c.int, buf: ^byte, nbyte: u64) -> i64 {
 	return cast(i64)intrinsics.syscall(unix_offset_syscall(.read), uintptr(fildes), uintptr(buf), uintptr(nbyte))
 }
 
-syscall_open :: #force_inline proc(path: cstring, oflag: u32, mode: u32) -> c.int {
+syscall_open :: #force_inline proc "contextless" (path: cstring, oflag: u32, mode: u32) -> c.int {
 	return cast(c.int)intrinsics.syscall(unix_offset_syscall(.open), transmute(uintptr)path, uintptr(oflag), uintptr(mode))
 }
 
-syscall_close :: #force_inline proc(fd: c.int) -> bool {
+syscall_close :: #force_inline proc "contextless" (fd: c.int) -> bool {
 	return !(cast(bool)intrinsics.syscall(unix_offset_syscall(.close), uintptr(fd)))
 }
 
-syscall_fchmod :: #force_inline proc(fildes: c.int, mode: u32) -> c.int {
+syscall_fchmod :: #force_inline proc "contextless" (fildes: c.int, mode: u32) -> c.int {
 	return (cast(c.int)intrinsics.syscall(unix_offset_syscall(.fchmod), uintptr(fildes), uintptr(mode)))
 }
 
-syscall_chmod :: #force_inline proc(path: cstring, mode: u32) -> c.int {
+syscall_chmod :: #force_inline proc "contextless" (path: cstring, mode: u32) -> c.int {
 	return (cast(c.int)intrinsics.syscall(unix_offset_syscall(.chmod), transmute(uintptr)path, uintptr(mode)))
 }
 
-syscall_mkdir :: #force_inline proc(path: cstring, mode: u32) -> c.int {
+syscall_mkdir :: #force_inline proc "contextless" (path: cstring, mode: u32) -> c.int {
 	return (cast(c.int)intrinsics.syscall(unix_offset_syscall(.mkdir), transmute(uintptr)path, uintptr(mode)))
 }
 
-syscall_mkdir_at :: #force_inline proc(fd: c.int, path: cstring, mode: u32) -> c.int {
+syscall_mkdir_at :: #force_inline proc "contextless" (fd: c.int, path: cstring, mode: u32) -> c.int {
 	return (cast(c.int)intrinsics.syscall(unix_offset_syscall(.mkdir), uintptr(fd), transmute(uintptr)path, uintptr(mode)))
 }
 
-syscall_rmdir :: #force_inline proc(path: cstring, mode: u32) -> c.int {
+syscall_rmdir :: #force_inline proc "contextless" (path: cstring, mode: u32) -> c.int {
 	return (cast(c.int)intrinsics.syscall(unix_offset_syscall(.rmdir), transmute(uintptr)path, uintptr(mode)))
 }
 
-syscall_rename :: #force_inline proc(path_old: cstring, path_new: cstring) -> c.int {
+syscall_rename :: #force_inline proc "contextless" (path_old: cstring, path_new: cstring) -> c.int {
 	return (cast(c.int)intrinsics.syscall(unix_offset_syscall(.rename), transmute(uintptr)path_old, transmute(uintptr)path_new))
 }
 
-syscall_rename_at :: #force_inline proc(from_fd: c.int, from: cstring, to_fd: c.int, to: cstring) -> c.int {
+syscall_rename_at :: #force_inline proc "contextless" (from_fd: c.int, from: cstring, to_fd: c.int, to: cstring) -> c.int {
 	return (cast(c.int)intrinsics.syscall(unix_offset_syscall(.renameat), uintptr(from_fd), transmute(uintptr)from, uintptr(to_fd), transmute(uintptr)to))
 }
 
-syscall_lseek :: #force_inline proc(fd: c.int, offset: i64, whence: c.int) -> i64 {
+syscall_lseek :: #force_inline proc "contextless" (fd: c.int, offset: i64, whence: c.int) -> i64 {
 	return cast(i64)intrinsics.syscall(unix_offset_syscall(.lseek), uintptr(fd), uintptr(offset), uintptr(whence))
 }
 
-syscall_gettid :: #force_inline proc() -> u64 {
+syscall_gettid :: #force_inline proc "contextless" () -> u64 {
 	return cast(u64)intrinsics.syscall(unix_offset_syscall(.gettid))
 }
 
-syscall_fstat :: #force_inline proc(fd: c.int, status: ^stat) -> c.int {
+syscall_fstat :: #force_inline proc "contextless" (fd: c.int, status: ^stat) -> c.int {
 	return cast(c.int)intrinsics.syscall(unix_offset_syscall(.fstat), uintptr(fd), uintptr(status))
 }
 
-syscall_lstat :: #force_inline proc(path: cstring, status: ^stat) -> c.int {
+syscall_lstat :: #force_inline proc "contextless" (path: cstring, status: ^stat) -> c.int {
 	return cast(c.int)intrinsics.syscall(unix_offset_syscall(.lstat), transmute(uintptr)path, uintptr(status))
 }
 
-syscall_stat :: #force_inline proc(path: cstring, status: ^stat) -> c.int {
+syscall_stat :: #force_inline proc "contextless" (path: cstring, status: ^stat) -> c.int {
 	return cast(c.int)intrinsics.syscall(unix_offset_syscall(.stat), transmute(uintptr)path, uintptr(status))
 }
 
-syscall_fstatat :: #force_inline proc(fd: c.int, path: cstring, status: ^stat) -> c.int {
+syscall_fstatat :: #force_inline proc "contextless" (fd: c.int, path: cstring, status: ^stat) -> c.int {
 	return cast(c.int)intrinsics.syscall(unix_offset_syscall(.fstatat), uintptr(fd), transmute(uintptr)path, uintptr(status))
 }
 
-syscall_link :: #force_inline proc(path: cstring, to_link: cstring) -> c.int {
+syscall_link :: #force_inline proc "contextless" (path: cstring, to_link: cstring) -> c.int {
 	return cast(c.int)intrinsics.syscall(unix_offset_syscall(.link), transmute(uintptr)path, transmute(uintptr)to_link)
 }
 
-syscall_linkat :: #force_inline proc(fd: c.int, path: cstring, fd2: c.int, to_link: cstring) -> c.int {
+syscall_linkat :: #force_inline proc "contextless" (fd: c.int, path: cstring, fd2: c.int, to_link: cstring) -> c.int {
 	return cast(c.int)intrinsics.syscall(unix_offset_syscall(.linkat), uintptr(fd), transmute(uintptr)path, uintptr(fd2), transmute(uintptr)to_link)
 }
 
-syscall_readlink :: #force_inline proc(path: cstring, buf: ^u8, buf_size: u64) -> i64 {
+syscall_readlink :: #force_inline proc "contextless" (path: cstring, buf: ^u8, buf_size: u64) -> i64 {
 	return cast(i64)intrinsics.syscall(unix_offset_syscall(.readlink), transmute(uintptr)path, uintptr(buf), uintptr(buf_size))
 }
 
-syscall_readlinkat :: #force_inline proc(fd: c.int, path: cstring, buf: ^u8, buf_size: u64) -> i64 {
+syscall_readlinkat :: #force_inline proc "contextless" (fd: c.int, path: cstring, buf: ^u8, buf_size: u64) -> i64 {
 	return cast(i64)intrinsics.syscall(unix_offset_syscall(.readlinkat), uintptr(fd), transmute(uintptr)path, uintptr(buf), uintptr(buf_size))
 }
 
-syscall_access :: #force_inline proc(path: cstring, mode: c.int) -> c.int {
+syscall_access :: #force_inline proc "contextless" (path: cstring, mode: c.int) -> c.int {
 	return cast(c.int)intrinsics.syscall(unix_offset_syscall(.access), transmute(uintptr)path, uintptr(mode))
 }
 
-syscall_faccessat :: #force_inline proc(fd: c.int, path: cstring, mode: c.int, flag: c.int) -> c.int {
+syscall_faccessat :: #force_inline proc "contextless" (fd: c.int, path: cstring, mode: c.int, flag: c.int) -> c.int {
 	return cast(c.int)intrinsics.syscall(unix_offset_syscall(.faccessat), uintptr(fd), transmute(uintptr)path, uintptr(mode), uintptr(flag))
 }
 
-syscall_getdirentries :: #force_inline proc(fd: c.int, buf: ^u8, nbytes: c.int, base_pointer: ^u32) -> c.int {
+syscall_getdirentries :: #force_inline proc "contextless" (fd: c.int, buf: ^u8, nbytes: c.int, base_pointer: ^u32) -> c.int {
 	return cast(c.int)intrinsics.syscall(unix_offset_syscall(.getdirentries), uintptr(fd), uintptr(buf), uintptr(nbytes), uintptr(base_pointer))
 }
 
-syscall_truncate :: #force_inline proc (path: cstring, length: off_t) -> c.int {
+syscall_truncate :: #force_inline proc "contextless" (path: cstring, length: off_t) -> c.int {
 	return cast(c.int)intrinsics.syscall(unix_offset_syscall(.truncate), transmute(uintptr)path, uintptr(length))
 }
 
-syscall_ftruncate :: #force_inline proc (fd: c.int, length: off_t) -> c.int {
+syscall_ftruncate :: #force_inline proc "contextless" (fd: c.int, length: off_t) -> c.int {
 	return cast(c.int)intrinsics.syscall(unix_offset_syscall(.ftruncate), uintptr(fd), uintptr(length))
 }
 
-syscall_sysctl :: #force_inline proc (name: ^c.int, namelen: c.uint, oldp: rawptr, oldlenp: ^i64, newp: ^i8, newlen: i64) -> c.int {
+syscall_sysctl :: #force_inline proc "contextless" (name: ^c.int, namelen: c.uint, oldp: rawptr, oldlenp: ^i64, newp: ^i8, newlen: i64) -> c.int {
 	return cast(c.int)intrinsics.syscall(unix_offset_syscall(.sysctl), uintptr(name), uintptr(namelen), uintptr(oldp), uintptr(oldlenp), uintptr(newp), uintptr(newlen))
 }
 
-syscall_copyfile ::  #force_inline proc(from: cstring, to: cstring, state: rawptr, flags: u32) -> c.int {
+syscall_copyfile ::  #force_inline proc "contextless" (from: cstring, to: cstring, state: rawptr, flags: u32) -> c.int {
 	return cast(c.int)intrinsics.syscall(unix_offset_syscall(.copyfile), transmute(uintptr)from, transmute(uintptr)to, uintptr(state), uintptr(flags))
 } 
 
 // think about this? last arg should be more than one
-syscall_fcntl :: #force_inline proc(fd: c.int, cmd: c.int, other: rawptr) -> c.int {
+syscall_fcntl :: #force_inline proc "contextless" (fd: c.int, cmd: c.int, other: rawptr) -> c.int {
 	return cast(c.int)intrinsics.syscall(unix_offset_syscall(.fsctl), uintptr(fd), uintptr(cmd), uintptr(other))
 }
 
-syscall_exit :: #force_inline proc(code: c.int) {
+syscall_exit :: #force_inline proc "contextless" (code: c.int) {
 	intrinsics.syscall(unix_offset_syscall(.exit), uintptr(code))
 }
 
-syscall_kill :: #force_inline proc(pid: pid_t, sig: c.int) -> c.int {
+syscall_kill :: #force_inline proc "contextless" (pid: pid_t, sig: c.int) -> c.int {
 	return cast(c.int)intrinsics.syscall(unix_offset_syscall(.kill), uintptr(pid), uintptr(sig))
 }
 
-syscall_dup :: #force_inline proc(fd: c.int) -> c.int {
+syscall_dup :: #force_inline proc "contextless" (fd: c.int) -> c.int {
 	return cast(c.int)intrinsics.syscall(unix_offset_syscall(.dup), uintptr(fd))
 }
 
-syscall_execve :: #force_inline proc(path: cstring, argv: [^]cstring, env: [^]cstring) -> c.int {
+syscall_execve :: #force_inline proc "contextless" (path: cstring, argv: [^]cstring, env: [^]cstring) -> c.int {
 	return cast(c.int)intrinsics.syscall(unix_offset_syscall(.execve), transmute(uintptr)path, transmute(uintptr)argv, transmute(uintptr)env)
 }
 
-syscall_munmap :: #force_inline proc(addr: rawptr, len: u64) -> c.int {
+syscall_munmap :: #force_inline proc "contextless" (addr: rawptr, len: u64) -> c.int {
 	return cast(c.int)intrinsics.syscall(unix_offset_syscall(.mmap), uintptr(addr), uintptr(len))
 }
 
-syscall_mmap :: #force_inline proc(addr: ^u8, len: u64, port: c.int, flags: c.int, fd: int, offset: off_t) -> ^u8 {
+syscall_mmap :: #force_inline proc "contextless" (addr: ^u8, len: u64, port: c.int, flags: c.int, fd: int, offset: off_t) -> ^u8 {
 	return cast(^u8)intrinsics.syscall(unix_offset_syscall(.mmap), uintptr(addr), uintptr(len), uintptr(port), uintptr(flags), uintptr(fd), uintptr(offset))
 }
 
-syscall_flock :: #force_inline proc(fd: c.int, operation: c.int) -> c.int {
+syscall_flock :: #force_inline proc "contextless" (fd: c.int, operation: c.int) -> c.int {
 	return cast(c.int)intrinsics.syscall(unix_offset_syscall(.flock), uintptr(fd), uintptr(operation)) 
 }
 
-syscall_utimes :: #force_inline proc(path: cstring, times: ^timeval) -> c.int {
+syscall_utimes :: #force_inline proc "contextless" (path: cstring, times: ^timeval) -> c.int {
 	return cast(c.int)intrinsics.syscall(unix_offset_syscall(.utimes), transmute(uintptr)path, uintptr(times))
 }
 
-syscall_futimes :: #force_inline proc(fd: c.int, times: ^timeval) -> c.int {
+syscall_futimes :: #force_inline proc "contextless" (fd: c.int, times: ^timeval) -> c.int {
 	return cast(c.int)intrinsics.syscall(unix_offset_syscall(.futimes), uintptr(fd), uintptr(times))
 }
 
-syscall_adjtime :: #force_inline proc(delta: ^timeval, old_delta: ^timeval) -> c.int {
+syscall_adjtime :: #force_inline proc "contextless" (delta: ^timeval, old_delta: ^timeval) -> c.int {
 	return cast(c.int)intrinsics.syscall(unix_offset_syscall(.adjtime), uintptr(delta), uintptr(old_delta))
 }
 
-syscall_sysctlbyname :: #force_inline proc(name: cstring, oldp: rawptr, oldlenp: ^i64, newp: rawptr, newlen: i64) -> c.int {
+syscall_sysctlbyname :: #force_inline proc "contextless" (name: cstring, oldp: rawptr, oldlenp: ^i64, newp: rawptr, newlen: i64) -> c.int {
 	return cast(c.int)intrinsics.syscall(unix_offset_syscall(.sysctlbyname), transmute(uintptr)name, uintptr(oldp), uintptr(oldlenp), uintptr(newp), uintptr(newlen))
 }
 
-syscall_proc_info :: #force_inline proc(num: c.int, pid: u32, flavor: c.int, arg: u64, buffer: rawptr, buffer_size: c.int) -> c.int {
+syscall_proc_info :: #force_inline proc "contextless" (num: c.int, pid: u32, flavor: c.int, arg: u64, buffer: rawptr, buffer_size: c.int) -> c.int {
 	return cast(c.int)intrinsics.syscall(unix_offset_syscall(.proc_info), uintptr(num), uintptr(pid), uintptr(flavor), uintptr(arg), uintptr(buffer), uintptr(buffer_size))
 }
 
-syscall_openat :: #force_inline proc(fd: int, path: cstring, oflag: u32, mode: u32) -> c.int {
+syscall_openat :: #force_inline proc "contextless" (fd: int, path: cstring, oflag: u32, mode: u32) -> c.int {
 	return cast(c.int)intrinsics.syscall(unix_offset_syscall(.openat), uintptr(fd), transmute(uintptr)path, uintptr(oflag), uintptr(mode))
 } 
 
-syscall_getentropy :: #force_inline proc(buf: [^]u8, buflen: u64) -> c.int {
+syscall_getentropy :: #force_inline proc "contextless" (buf: [^]u8, buflen: u64) -> c.int {
 	return cast(c.int)intrinsics.syscall(unix_offset_syscall(.getentropy), uintptr(buf), uintptr(buflen))
 }
 
-syscall_pipe :: #force_inline proc(fds: [^]c.int) -> c.int {
+syscall_pipe :: #force_inline proc "contextless" (fds: [^]c.int) -> c.int {
 	return cast(c.int)intrinsics.syscall(unix_offset_syscall(.getentropy), uintptr(&fds[0]), uintptr(&fds[1]))
 }
 
-syscall_chdir :: #force_inline proc(path: cstring) -> c.int {
+syscall_chdir :: #force_inline proc "contextless" (path: cstring) -> c.int {
 	return cast(c.int)intrinsics.syscall(unix_offset_syscall(.getentropy), transmute(uintptr)path)
 }
 
-syscall_fchdir :: #force_inline proc(fd: c.int, path: cstring) -> c.int {
+syscall_fchdir :: #force_inline proc "contextless" (fd: c.int, path: cstring) -> c.int {
 	return cast(c.int)intrinsics.syscall(unix_offset_syscall(.getentropy), uintptr(fd), transmute(uintptr)path)
-}
+}

+ 153 - 0
core/sys/unix/syscalls_linux.odin

@@ -1563,6 +1563,155 @@ MADV_WIPEONFORK  :: 18
 MADV_KEEPONFORK  :: 19
 MADV_HWPOISON    :: 100
 
+// perf event data
+Perf_Sample :: struct #raw_union {
+	period:    u64,
+	frequency: u64,
+}
+Perf_Wakeup :: struct #raw_union {
+	events:    u32,
+	watermark: u32,
+}
+Perf_Field1 :: struct #raw_union {
+	breakpoint_addr: u64,
+	kprobe_func:     u64,
+	uprobe_path:     u64,
+	config1:         u64,
+}
+Perf_Field2 :: struct #raw_union {
+	breakpoint_len: u64,
+	kprobe_addr:    u64,
+	uprobe_offset:  u64,
+	config2:        u64,
+}
+Perf_Event_Attr :: struct #packed {
+	type:   u32,
+	size:   u32,
+	config: u64,
+	sample: Perf_Sample,
+	sample_type: u64,
+	read_format: u64,
+	flags:       Perf_Flags,
+	wakeup: Perf_Wakeup,
+	breakpoint_type: u32,
+	field1: Perf_Field1,
+	field2: Perf_Field2,
+	branch_sample_type: u64,
+	sample_regs_user:   u64,
+	sample_stack_user:  u32,
+	clock_id:           i32,
+	sample_regs_intr:   u64,
+	aux_watermark:      u32,
+	sample_max_stack:   u16,
+	_padding:           u16,
+}
+
+Perf_Event_Flags :: distinct bit_set[Perf_Event_Flag; u64]
+Perf_Event_Flag :: enum u64 {
+	Bit0               = 0,
+	Bit0_Is_Deprecated = 1,
+	User_Rdpmc         = 2,
+	User_Time          = 3,
+	User_Time_Zero     = 4,
+	User_Time_Short    = 5,
+}
+Perf_Capabilities :: struct #raw_union {
+	capabilities: u64,
+	flags: Perf_Event_Flags,
+}
+Perf_Event_mmap_Page :: struct #packed {
+	version:        u32,
+	compat_version: u32,
+	lock:           u32,
+	index:          u32,
+	offset:         i64,
+	time_enabled:   u64,
+	time_running:   u64,
+	cap: Perf_Capabilities,
+	pmc_width:      u16,
+	time_shift:     u16,
+	time_mult:      u32,
+	time_offset:    u64,
+	time_zero:      u64,
+	size:           u32,
+	reserved1:      u32,
+	time_cycles:    u64,
+	time_mask:      u64,
+	reserved2:      [116*8]u8,
+	data_head:      u64,
+	data_tail:      u64,
+	data_offset:    u64,
+	data_size:      u64,
+	aux_head:       u64,
+	aux_tail:       u64,
+	aux_offset:     u64,
+	aux_size:       u64,
+}
+
+Perf_Type_Id :: enum u32 {
+	Hardware   = 0,
+	Software   = 1,
+	Tracepoint = 2,
+	HW_Cache   = 3,
+	Raw        = 4,
+	Breakpoint = 5,
+}
+
+Perf_Hardware_Id :: enum u64 {
+	CPU_Cycles              = 0,
+	Instructions            = 1,
+	Cache_References        = 2,
+	Cache_Misses            = 3,
+	Branch_Instructions     = 4,
+	Branch_Misses           = 5,
+	Bus_Cycles              = 6,
+	Stalled_Cycles_Frontend = 7,
+	Stalled_Cycles_Backend  = 8,
+	Ref_CPU_Cycles          = 9,
+}
+
+Perf_Flags :: distinct bit_set[Perf_Flag; u64]
+Perf_Flag :: enum u64 {
+	Disabled       = 0,
+	Inherit        = 1,
+	Pinned         = 2,
+	Exclusive      = 3,
+	Exclude_User   = 4,
+	Exclude_Kernel = 5,
+	Exclude_HV     = 6,
+	Exclude_Idle   = 7,
+	mmap           = 8,
+	Comm           = 9,
+	Freq           = 10,
+	Inherit_Stat   = 11,
+	Enable_On_Exec = 12,
+	Task           = 13,
+	Watermark      = 14,
+	Precise_IP_0   = 15,
+	Precise_IP_1   = 16,
+	mmap_Data      = 17,
+	Sample_Id_All  = 18,
+	Exclude_Host   = 19,
+	Exclude_Guest  = 20,
+	Exclude_Callchain_Kernel = 21,
+	Exclude_Callchain_User   = 22,
+	mmap2          = 23,
+	Comm_Exec      = 24,
+	Use_Clockid    = 25,
+	Context_Switch = 26,
+	Write_Backward = 27,
+	Namespaces     = 28,
+	KSymbol        = 29,
+	BPF_Event      = 30,
+	Aux_Output     = 31,
+	CGroup         = 32,
+	Text_Poke      = 33,
+	Build_Id       = 34,
+	Inherit_Thread = 35,
+	Remove_On_Exec = 36,
+	Sigtrap        = 37,
+}
+
 sys_gettid :: proc "contextless" () -> int {
 	return cast(int)intrinsics.syscall(SYS_gettid)
 }
@@ -1846,6 +1995,10 @@ sys_utimensat :: proc "contextless" (dfd: int, path: cstring, times: rawptr, fla
 	return int(intrinsics.syscall(SYS_utimensat, uintptr(dfd), uintptr(rawptr(path)), uintptr(times), uintptr(flags)))
 }
 
+sys_perf_event_open :: proc "contextless" (event_attr: rawptr, pid: i32, cpu: i32, group_fd: i32, flags: u32) -> int {
+	return int(intrinsics.syscall(SYS_perf_event_open, uintptr(event_attr), uintptr(pid), uintptr(cpu), uintptr(group_fd), uintptr(flags)))
+}
+
 get_errno :: proc "contextless" (res: int) -> i32 {
 	if res < 0 && res > -4096 {
 		return i32(-res)

+ 49 - 2
core/time/perf.odin

@@ -1,11 +1,11 @@
 package time
 
 import "core:runtime"
+import "core:intrinsics"
 
 Tick :: struct {
 	_nsec: i64, // relative amount
 }
-
 tick_now :: proc "contextless" () -> Tick {
 	return _tick_now()
 }
@@ -40,6 +40,53 @@ _tick_duration_end :: proc "contextless" (d: ^Duration, t: Tick) {
 	d^ = tick_since(t)
 }
 
+when ODIN_ARCH == .amd64 {
+	@(private)
+	x86_has_invariant_tsc :: proc "contextless" () -> bool {
+		eax, _, _, _ := intrinsics.x86_cpuid(0x80_000_000, 0)
+
+		// Is this processor *really* ancient?
+		if eax < 0x80_000_007 {
+			return false
+		}
+
+		// check if the invariant TSC bit is set
+		_, _, _, edx := intrinsics.x86_cpuid(0x80_000_007, 0)
+		return (edx & (1 << 8)) != 0
+	}
+}
+
+has_invariant_tsc :: proc "contextless" () -> bool {
+	when ODIN_ARCH == .amd64 {
+		return x86_has_invariant_tsc()
+	}
+
+	return false
+}
+
+tsc_frequency :: proc "contextless" () -> (u64, bool) {
+	if !has_invariant_tsc() {
+		return 0, false
+	}
+
+	hz, ok := _get_tsc_frequency()
+	if !ok {
+		// fallback to approximate TSC
+		tsc_begin := intrinsics.read_cycle_counter()
+		tick_begin := tick_now()
+
+		sleep(2 * Second)
+
+		tsc_end := intrinsics.read_cycle_counter()
+		tick_end := tick_now()
+
+		time_diff := u128(duration_nanoseconds(tick_diff(tick_begin, tick_end)))
+		hz = u64((u128(tsc_end - tsc_begin) * 1_000_000_000) / time_diff)
+	}
+
+	return hz, true
+}
+
 /*
 	Benchmark helpers
 */
@@ -94,4 +141,4 @@ benchmark :: proc(options: ^Benchmark_Options, allocator := context.allocator) -
 		options->teardown(allocator) or_return
 	}
 	return
-}
+}

+ 21 - 0
core/time/tsc_darwin.odin

@@ -0,0 +1,21 @@
+//+private
+//+build darwin
+package time
+
+import "core:c"
+
+foreign import libc "System.framework"
+foreign libc {
+	@(link_name="sysctlbyname") _sysctlbyname    :: proc(path: cstring, oldp: rawptr, oldlenp: rawptr, newp: rawptr, newlen: int) -> c.int ---
+}
+
+_get_tsc_frequency :: proc "contextless" () -> (u64, bool) {
+	tmp_freq : u64 = 0
+	tmp_size : i64 = size_of(tmp_freq)
+	ret := _sysctlbyname("machdep.tsc.frequency", &tmp_freq, &tmp_size, nil, 0)
+	if ret < 0 {
+		return 0, false
+	}
+
+	return tmp_freq, true
+}

+ 21 - 0
core/time/tsc_freebsd.odin

@@ -0,0 +1,21 @@
+//+private
+//+build freebsd
+package time
+
+import "core:c"
+
+foreign import libc "system:c"
+foreign libc {
+	@(link_name="sysctlbyname") _sysctlbyname :: proc(path: cstring, oldp: rawptr, oldlenp: rawptr, newp: rawptr, newlen: int) -> c.int ---
+}
+
+_get_tsc_frequency :: proc "contextless" () -> (u64, bool) {
+	tmp_freq : u64 = 0
+	tmp_size : i64 = size_of(tmp_freq)
+	ret := _sysctlbyname("machdep.tsc_freq", &tmp_freq, &tmp_size, nil, 0)
+	if ret < 0 {
+		return 0, false
+	}
+
+	return tmp_freq, true
+}

+ 35 - 0
core/time/tsc_linux.odin

@@ -0,0 +1,35 @@
+//+private
+//+build linux
+package time
+
+import "core:intrinsics"
+import "core:sys/unix"
+
+_get_tsc_frequency :: proc "contextless" () -> (u64, bool) {
+	perf_attr := unix.Perf_Event_Attr{}
+	perf_attr.type = u32(unix.Perf_Type_Id.Hardware)
+	perf_attr.config = u64(unix.Perf_Hardware_Id.Instructions)
+	perf_attr.size = size_of(perf_attr)
+	perf_attr.flags = {.Disabled, .Exclude_Kernel, .Exclude_HV}
+	fd := unix.sys_perf_event_open(&perf_attr, 0, -1, -1, 0)
+	if fd == -1 {
+		return 0, false
+	}
+	defer unix.sys_close(fd)
+
+	page_size : uint = 4096
+	ret := unix.sys_mmap(nil, page_size, unix.PROT_READ, unix.MAP_SHARED, fd, 0)
+	if ret < 0 && ret > -4096 {
+		return 0, false
+	}
+	addr := rawptr(uintptr(ret))
+	defer unix.sys_munmap(addr, page_size)
+
+	event_page := (^unix.Perf_Event_mmap_Page)(addr)
+	if .User_Time not_in event_page.cap.flags {
+		return 0, false
+	}
+
+	frequency := u64((u128(1_000_000_000) << u128(event_page.time_shift)) / u128(event_page.time_mult))
+	return frequency, true
+}

+ 7 - 0
core/time/tsc_openbsd.odin

@@ -0,0 +1,7 @@
+//+private
+//+build openbsd
+package time
+
+_get_tsc_frequency :: proc "contextless" () -> (u64, bool) {
+	return 0, false
+}

+ 7 - 0
core/time/tsc_windows.odin

@@ -0,0 +1,7 @@
+//+private
+//+build windows
+package time
+
+_get_tsc_frequency :: proc "contextless" () -> (u64, bool) {
+	return 0, false
+}

+ 0 - 1
src/check_stmt.cpp

@@ -1293,7 +1293,6 @@ gb_internal void check_type_switch_stmt(CheckerContext *ctx, Ast *node, u32 mod_
 		for (Type *t : variants) {
 			if (!type_ptr_set_exists(&seen, t)) {
 				array_add(&unhandled, t);
-				gb_printf_err("HERE: %p %s\n", t, type_to_string(t));
 			}
 		}