mirror of
https://github.com/Ed94/Odin.git
synced 2026-08-04 22:58:46 +00:00
Merge tag 'dev-2025-06'
This commit is contained in:
+229
-7
@@ -7,13 +7,232 @@ nil :: nil
|
||||
false :: 0!=0
|
||||
true :: 0==0
|
||||
|
||||
ODIN_OS :: ODIN_OS
|
||||
ODIN_ARCH :: ODIN_ARCH
|
||||
ODIN_ENDIAN :: ODIN_ENDIAN
|
||||
ODIN_VENDOR :: ODIN_VENDOR
|
||||
ODIN_VERSION :: ODIN_VERSION
|
||||
ODIN_ROOT :: ODIN_ROOT
|
||||
ODIN_DEBUG :: ODIN_DEBUG
|
||||
// The following constants are added in `checker.cpp`'s `init_universal` procedure.
|
||||
|
||||
/*
|
||||
An `enum` value indicating the target's CPU architecture.
|
||||
Possible values are: `.amd64`, `.i386`, `.arm32`, `.arm64`, `.wasm32`, `.wasm64p32`, and `.riscv64`.
|
||||
*/
|
||||
ODIN_ARCH :: ODIN_ARCH
|
||||
|
||||
/*
|
||||
A `string` indicating the target's CPU architecture.
|
||||
Possible values are: "amd64", "i386", "arm32", "arm64", "wasm32", "wasm64p32", "riscv64".
|
||||
*/
|
||||
ODIN_ARCH_STRING :: ODIN_ARCH_STRING
|
||||
|
||||
/*
|
||||
An `enum` value indicating the type of compiled output, chosen using `-build-mode`.
|
||||
Possible values are: `.Executable`, `.Dynamic`, `.Static`, `.Object`, `.Assembly`, and `.LLVM_IR`.
|
||||
*/
|
||||
ODIN_BUILD_MODE :: ODIN_BUILD_MODE
|
||||
|
||||
/*
|
||||
A `string` containing the name of the folder that contains the entry point,
|
||||
e.g. for `%ODIN_ROOT%/examples/demo`, this would contain `demo`.
|
||||
*/
|
||||
ODIN_BUILD_PROJECT_NAME :: ODIN_BUILD_PROJECT_NAME
|
||||
|
||||
/*
|
||||
An `i64` containing the time at which the executable was compiled, in nanoseconds.
|
||||
This is compatible with the `time.Time` type, i.e. `time.Time{_nsec=ODIN_COMPILE_TIMESTAMP}`
|
||||
*/
|
||||
ODIN_COMPILE_TIMESTAMP :: ODIN_COMPILE_TIMESTAMP
|
||||
|
||||
/*
|
||||
`true` if the `-debug` command line switch is passed, which enables debug info generation.
|
||||
*/
|
||||
ODIN_DEBUG :: ODIN_DEBUG
|
||||
|
||||
/*
|
||||
`true` if the `-default-to-nil-allocator` command line switch is passed,
|
||||
which sets the initial `context.allocator` to an allocator that does nothing.
|
||||
*/
|
||||
ODIN_DEFAULT_TO_NIL_ALLOCATOR :: ODIN_DEFAULT_TO_NIL_ALLOCATOR
|
||||
|
||||
/*
|
||||
`true` if the `-default-to-panic-allocator` command line switch is passed,
|
||||
which sets the initial `context.allocator` to an allocator that panics if allocated from.
|
||||
*/
|
||||
ODIN_DEFAULT_TO_PANIC_ALLOCATOR :: ODIN_DEFAULT_TO_PANIC_ALLOCATOR
|
||||
|
||||
/*
|
||||
`true` if the `-disable-assert` command line switch is passed,
|
||||
which removes all calls to `assert` from the program.
|
||||
*/
|
||||
ODIN_DISABLE_ASSERT :: ODIN_DISABLE_ASSERT
|
||||
|
||||
/*
|
||||
An `enum` value indicating the endianness of the target.
|
||||
Possible values are: `.Little` and `.Big`.
|
||||
*/
|
||||
ODIN_ENDIAN :: ODIN_ENDIAN
|
||||
|
||||
/*
|
||||
An `string` indicating the endianness of the target.
|
||||
Possible values are: "little" and "big".
|
||||
*/
|
||||
ODIN_ENDIAN_STRING :: ODIN_ENDIAN_STRING
|
||||
|
||||
/*
|
||||
An `enum` value set using the `-error-pos-style` switch, indicating the source location style used for compile errors and warnings.
|
||||
Possible values are: `.Default` (Odin-style) and `.Unix`.
|
||||
*/
|
||||
ODIN_ERROR_POS_STYLE :: ODIN_ERROR_POS_STYLE
|
||||
|
||||
/*
|
||||
`true` if the `-foreign-error-procedures` command line switch is passed,
|
||||
which inhibits generation of runtime error procedures, so that they can be in a separate compilation unit.
|
||||
*/
|
||||
ODIN_FOREIGN_ERROR_PROCEDURES :: ODIN_FOREIGN_ERROR_PROCEDURES
|
||||
|
||||
/*
|
||||
A `string` describing the microarchitecture used for code generation.
|
||||
If not set using the `-microarch` command line switch, the compiler will pick a default.
|
||||
Possible values include, but are not limited to: "sandybridge", "x86-64-v2".
|
||||
*/
|
||||
ODIN_MICROARCH_STRING :: ODIN_MICROARCH_STRING
|
||||
|
||||
/*
|
||||
An `int` value representing the minimum OS version given to the linker, calculated as `major * 10_000 + minor * 100 + revision`.
|
||||
If not set using the `-minimum-os-version` command line switch, it defaults to `0`, except on Darwin, where it's `11_00_00`.
|
||||
*/
|
||||
ODIN_MINIMUM_OS_VERSION :: ODIN_MINIMUM_OS_VERSION
|
||||
|
||||
/*
|
||||
`true` if the `-no-bounds-check` command line switch is passed, which disables bounds checking at runtime.
|
||||
*/
|
||||
ODIN_NO_BOUNDS_CHECK :: ODIN_NO_BOUNDS_CHECK
|
||||
|
||||
/*
|
||||
`true` if the `-no-crt` command line switch is passed, which inhibits linking with the C Runtime Library, a.k.a. LibC.
|
||||
*/
|
||||
ODIN_NO_CRT :: ODIN_NO_CRT
|
||||
|
||||
/*
|
||||
`true` if the `-no-entry-point` command line switch is passed, which makes the declaration of a `main` procedure optional.
|
||||
*/
|
||||
ODIN_NO_ENTRY_POINT :: ODIN_NO_ENTRY_POINT
|
||||
|
||||
/*
|
||||
`true` if the `-no-rtti` command line switch is passed, which inhibits generation of full Runtime Type Information.
|
||||
*/
|
||||
ODIN_NO_RTTI :: ODIN_NO_RTTI
|
||||
|
||||
/*
|
||||
`true` if the `-no-type-assert` command line switch is passed, which disables type assertion checking program wide.
|
||||
*/
|
||||
ODIN_NO_TYPE_ASSERT :: ODIN_NO_TYPE_ASSERT
|
||||
|
||||
/*
|
||||
An `enum` value indicating the optimization level selected using the `-o` command line switch.
|
||||
Possible values are: `.None`, `.Minimal`, `.Size`, `.Speed`, and `.Aggressive`.
|
||||
|
||||
If `ODIN_OPTIMIZATION_MODE` is anything other than `.None` or `.Minimal`, the compiler will also perform a unity build,
|
||||
and `ODIN_USE_SEPARATE_MODULES` will be set to `false` as a result.
|
||||
*/
|
||||
ODIN_OPTIMIZATION_MODE :: ODIN_OPTIMIZATION_MODE
|
||||
|
||||
/*
|
||||
An `enum` value indicating what the target operating system is.
|
||||
*/
|
||||
ODIN_OS :: ODIN_OS
|
||||
|
||||
/*
|
||||
A `string` indicating what the target operating system is.
|
||||
*/
|
||||
ODIN_OS_STRING :: ODIN_OS_STRING
|
||||
|
||||
/*
|
||||
An `enum` value indicating the platform subtarget, chosen using the `-subtarget` switch.
|
||||
Possible values are: `.Default` `.iOS`, and `.Android`.
|
||||
*/
|
||||
ODIN_PLATFORM_SUBTARGET :: ODIN_PLATFORM_SUBTARGET
|
||||
|
||||
/*
|
||||
A `string` representing the path of the folder containing the Odin compiler,
|
||||
relative to which we expect to find the `base` and `core` package collections.
|
||||
*/
|
||||
ODIN_ROOT :: ODIN_ROOT
|
||||
|
||||
/*
|
||||
A `bit_set` indicating the sanitizer flags set using the `-sanitize` command line switch.
|
||||
Supported flags are `.Address`, `.Memory`, and `.Thread`.
|
||||
*/
|
||||
ODIN_SANITIZER_FLAGS :: ODIN_SANITIZER_FLAGS
|
||||
|
||||
/*
|
||||
`true` if the code is being compiled via an invocation of `odin test`.
|
||||
*/
|
||||
ODIN_TEST :: ODIN_TEST
|
||||
|
||||
/*
|
||||
`true` if built using the experimental Tilde backend.
|
||||
*/
|
||||
ODIN_TILDE :: ODIN_TILDE
|
||||
|
||||
/*
|
||||
`true` by default, meaning each each package is built into its own object file, and then linked together.
|
||||
`false` if the `-use-single-module` command line switch to force a unity build is provided.
|
||||
|
||||
If `ODIN_OPTIMIZATION_MODE` is anything other than `.None` or `.Minimal`, the compiler will also perform a unity build,
|
||||
and this constant will also be set to `false`.
|
||||
*/
|
||||
ODIN_USE_SEPARATE_MODULES :: ODIN_USE_SEPARATE_MODULES
|
||||
|
||||
/*
|
||||
`true` if Valgrind integration is supported on the target.
|
||||
*/
|
||||
ODIN_VALGRIND_SUPPORT :: ODIN_VALGRIND_SUPPORT
|
||||
|
||||
/*
|
||||
A `string` which identifies the compiler being used. The official compiler sets this to `"odin"`.
|
||||
*/
|
||||
ODIN_VENDOR :: ODIN_VENDOR
|
||||
|
||||
/*
|
||||
A `string` containing the version of the Odin compiler, typically in the format `dev-YYYY-MM`.
|
||||
*/
|
||||
ODIN_VERSION :: ODIN_VERSION
|
||||
|
||||
/*
|
||||
A `string` containing the Git hash part of the Odin version.
|
||||
Empty if `.git` could not be detected at the time the compiler was built.
|
||||
*/
|
||||
ODIN_VERSION_HASH :: ODIN_VERSION_HASH
|
||||
|
||||
/*
|
||||
An `enum` set by the `-subsystem` flag, specifying which Windows subsystem the PE file was created for.
|
||||
Possible values are:
|
||||
`.Unknown` - Default and only value on non-Windows platforms
|
||||
`.Console` - Default on Windows
|
||||
`.Windows` - Can be used by graphical applications so Windows doesn't open an empty console
|
||||
|
||||
There are some other possible values for e.g. EFI applications, but only Console and Windows are supported.
|
||||
|
||||
See also: https://learn.microsoft.com/en-us/windows/win32/api/winnt/ns-winnt-image_optional_header64
|
||||
*/
|
||||
ODIN_WINDOWS_SUBSYSTEM :: ODIN_WINDOWS_SUBSYSTEM
|
||||
|
||||
/*
|
||||
An `string` set by the `-subsystem` flag, specifying which Windows subsystem the PE file was created for.
|
||||
Possible values are:
|
||||
"UNKNOWN" - Default and only value on non-Windows platforms
|
||||
"CONSOLE" - Default on Windows
|
||||
"WINDOWS" - Can be used by graphical applications so Windows doesn't open an empty console
|
||||
|
||||
There are some other possible values for e.g. EFI applications, but only Console and Windows are supported.
|
||||
|
||||
See also: https://learn.microsoft.com/en-us/windows/win32/api/winnt/ns-winnt-image_optional_header64
|
||||
*/
|
||||
ODIN_WINDOWS_SUBSYSTEM_STRING :: ODIN_WINDOWS_SUBSYSTEM_STRING
|
||||
|
||||
/*
|
||||
`true` if LLVM supports the f16 type.
|
||||
*/
|
||||
__ODIN_LLVM_F16_SUPPORTED :: __ODIN_LLVM_F16_SUPPORTED
|
||||
|
||||
|
||||
|
||||
byte :: u8 // alias
|
||||
|
||||
@@ -131,3 +350,6 @@ soa_zip :: proc(slices: ...) -> #soa[]Struct ---
|
||||
soa_unzip :: proc(value: $S/#soa[]$E) -> (slices: ...) ---
|
||||
|
||||
unreachable :: proc() -> ! ---
|
||||
|
||||
// Where T is a string, slice, dynamic array, or pointer to an array type
|
||||
raw_data :: proc(t: $T) -> rawptr
|
||||
+209
-112
@@ -16,6 +16,12 @@ RUNTIME_REQUIRE :: false // !ODIN_TILDE
|
||||
@(private)
|
||||
__float16 :: f16 when __ODIN_LLVM_F16_SUPPORTED else u16
|
||||
|
||||
HAS_HARDWARE_SIMD :: false when (ODIN_ARCH == .amd64 || ODIN_ARCH == .i386) && !intrinsics.has_target_feature("sse2") else
|
||||
false when (ODIN_ARCH == .arm64 || ODIN_ARCH == .arm32) && !intrinsics.has_target_feature("neon") else
|
||||
false when (ODIN_ARCH == .wasm64p32 || ODIN_ARCH == .wasm32) && !intrinsics.has_target_feature("simd128") else
|
||||
false when (ODIN_ARCH == .riscv64) && !intrinsics.has_target_feature("v") else
|
||||
true
|
||||
|
||||
|
||||
@(private)
|
||||
byte_slice :: #force_inline proc "contextless" (data: rawptr, len: int) -> []byte #no_bounds_check {
|
||||
@@ -229,151 +235,242 @@ memory_equal :: proc "contextless" (x, y: rawptr, n: int) -> bool {
|
||||
case n == 0: return true
|
||||
case x == y: return true
|
||||
}
|
||||
a, b := ([^]byte)(x), ([^]byte)(y)
|
||||
length := uint(n)
|
||||
a, b := cast([^]byte)x, cast([^]byte)y
|
||||
|
||||
for i := uint(0); i < length; i += 1 {
|
||||
n := uint(n)
|
||||
i := uint(0)
|
||||
m := uint(0)
|
||||
|
||||
if n >= 8 {
|
||||
when HAS_HARDWARE_SIMD {
|
||||
// Avoid using 256-bit SIMD on platforms where its emulation is
|
||||
// likely to be less than ideal.
|
||||
when ODIN_ARCH == .amd64 && intrinsics.has_target_feature("avx2") {
|
||||
m = n / 32 * 32
|
||||
for /**/; i < m; i += 32 {
|
||||
load_a := intrinsics.unaligned_load(cast(^#simd[32]u8)&a[i])
|
||||
load_b := intrinsics.unaligned_load(cast(^#simd[32]u8)&b[i])
|
||||
ne := intrinsics.simd_lanes_ne(load_a, load_b)
|
||||
if intrinsics.simd_reduce_or(ne) != 0 {
|
||||
return false
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
m = (n-i) / 16 * 16
|
||||
for /**/; i < m; i += 16 {
|
||||
load_a := intrinsics.unaligned_load(cast(^#simd[16]u8)&a[i])
|
||||
load_b := intrinsics.unaligned_load(cast(^#simd[16]u8)&b[i])
|
||||
ne := intrinsics.simd_lanes_ne(load_a, load_b)
|
||||
if intrinsics.simd_reduce_or(ne) != 0 {
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
m = (n-i) / 8 * 8
|
||||
for /**/; i < m; i += 8 {
|
||||
if intrinsics.unaligned_load(cast(^uintptr)&a[i]) != intrinsics.unaligned_load(cast(^uintptr)&b[i]) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for /**/; i < n; i += 1 {
|
||||
if a[i] != b[i] {
|
||||
return false
|
||||
}
|
||||
}
|
||||
return true
|
||||
|
||||
/*
|
||||
|
||||
when size_of(uint) == 8 {
|
||||
if word_length := length >> 3; word_length != 0 {
|
||||
for _ in 0..<word_length {
|
||||
if intrinsics.unaligned_load((^u64)(a)) != intrinsics.unaligned_load((^u64)(b)) {
|
||||
return false
|
||||
}
|
||||
a = a[size_of(u64):]
|
||||
b = b[size_of(u64):]
|
||||
}
|
||||
}
|
||||
|
||||
if length & 4 != 0 {
|
||||
if intrinsics.unaligned_load((^u32)(a)) != intrinsics.unaligned_load((^u32)(b)) {
|
||||
return false
|
||||
}
|
||||
a = a[size_of(u32):]
|
||||
b = b[size_of(u32):]
|
||||
}
|
||||
|
||||
if length & 2 != 0 {
|
||||
if intrinsics.unaligned_load((^u16)(a)) != intrinsics.unaligned_load((^u16)(b)) {
|
||||
return false
|
||||
}
|
||||
a = a[size_of(u16):]
|
||||
b = b[size_of(u16):]
|
||||
}
|
||||
|
||||
if length & 1 != 0 && a[0] != b[0] {
|
||||
return false
|
||||
}
|
||||
return true
|
||||
} else {
|
||||
if word_length := length >> 2; word_length != 0 {
|
||||
for _ in 0..<word_length {
|
||||
if intrinsics.unaligned_load((^u32)(a)) != intrinsics.unaligned_load((^u32)(b)) {
|
||||
return false
|
||||
}
|
||||
a = a[size_of(u32):]
|
||||
b = b[size_of(u32):]
|
||||
}
|
||||
}
|
||||
|
||||
length &= 3
|
||||
|
||||
if length != 0 {
|
||||
for i in 0..<length {
|
||||
if a[i] != b[i] {
|
||||
return false
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
*/
|
||||
|
||||
}
|
||||
memory_compare :: proc "contextless" (a, b: rawptr, n: int) -> int #no_bounds_check {
|
||||
|
||||
memory_compare :: proc "contextless" (x, y: rawptr, n: int) -> int #no_bounds_check {
|
||||
switch {
|
||||
case a == b: return 0
|
||||
case a == nil: return -1
|
||||
case b == nil: return +1
|
||||
case x == y: return 0
|
||||
case x == nil: return -1
|
||||
case y == nil: return +1
|
||||
}
|
||||
a, b := cast([^]byte)x, cast([^]byte)y
|
||||
|
||||
n := uint(n)
|
||||
i := uint(0)
|
||||
m := uint(0)
|
||||
|
||||
x := uintptr(a)
|
||||
y := uintptr(b)
|
||||
n := uintptr(n)
|
||||
|
||||
SU :: size_of(uintptr)
|
||||
fast := n/SU + 1
|
||||
offset := (fast-1)*SU
|
||||
curr_block := uintptr(0)
|
||||
if n < SU {
|
||||
fast = 0
|
||||
}
|
||||
|
||||
for /**/; curr_block < fast; curr_block += 1 {
|
||||
va := (^uintptr)(x + curr_block * size_of(uintptr))^
|
||||
vb := (^uintptr)(y + curr_block * size_of(uintptr))^
|
||||
if va ~ vb != 0 {
|
||||
for pos := curr_block*SU; pos < n; pos += 1 {
|
||||
a := (^byte)(x+pos)^
|
||||
b := (^byte)(y+pos)^
|
||||
if a ~ b != 0 {
|
||||
return -1 if (int(a) - int(b)) < 0 else +1
|
||||
when HAS_HARDWARE_SIMD {
|
||||
when ODIN_ARCH == .amd64 && intrinsics.has_target_feature("avx2") {
|
||||
m = n / 32 * 32
|
||||
for /**/; i < m; i += 32 {
|
||||
load_a := intrinsics.unaligned_load(cast(^#simd[32]u8)&a[i])
|
||||
load_b := intrinsics.unaligned_load(cast(^#simd[32]u8)&b[i])
|
||||
comparison := intrinsics.simd_lanes_ne(load_a, load_b)
|
||||
if intrinsics.simd_reduce_or(comparison) != 0 {
|
||||
sentinel: #simd[32]u8 = u8(0xFF)
|
||||
indices := intrinsics.simd_indices(#simd[32]u8)
|
||||
index_select := intrinsics.simd_select(comparison, indices, sentinel)
|
||||
index_reduce := cast(uint)intrinsics.simd_reduce_min(index_select)
|
||||
return -1 if a[i+index_reduce] < b[i+index_reduce] else +1
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for /**/; offset < n; offset += 1 {
|
||||
a := (^byte)(x+offset)^
|
||||
b := (^byte)(y+offset)^
|
||||
if a ~ b != 0 {
|
||||
return -1 if (int(a) - int(b)) < 0 else +1
|
||||
m = (n-i) / 16 * 16
|
||||
for /**/; i < m; i += 16 {
|
||||
load_a := intrinsics.unaligned_load(cast(^#simd[16]u8)&a[i])
|
||||
load_b := intrinsics.unaligned_load(cast(^#simd[16]u8)&b[i])
|
||||
comparison := intrinsics.simd_lanes_ne(load_a, load_b)
|
||||
if intrinsics.simd_reduce_or(comparison) != 0 {
|
||||
sentinel: #simd[16]u8 = u8(0xFF)
|
||||
indices := intrinsics.simd_indices(#simd[16]u8)
|
||||
index_select := intrinsics.simd_select(comparison, indices, sentinel)
|
||||
index_reduce := cast(uint)intrinsics.simd_reduce_min(index_select)
|
||||
return -1 if a[i+index_reduce] < b[i+index_reduce] else +1
|
||||
}
|
||||
}
|
||||
|
||||
// 64-bit SIMD is faster than using a `uintptr` to detect a difference then
|
||||
// re-iterating with the byte-by-byte loop, at least on AMD64.
|
||||
m = (n-i) / 8 * 8
|
||||
for /**/; i < m; i += 8 {
|
||||
load_a := intrinsics.unaligned_load(cast(^#simd[8]u8)&a[i])
|
||||
load_b := intrinsics.unaligned_load(cast(^#simd[8]u8)&b[i])
|
||||
comparison := intrinsics.simd_lanes_ne(load_a, load_b)
|
||||
if intrinsics.simd_reduce_or(comparison) != 0 {
|
||||
sentinel: #simd[8]u8 = u8(0xFF)
|
||||
indices := intrinsics.simd_indices(#simd[8]u8)
|
||||
index_select := intrinsics.simd_select(comparison, indices, sentinel)
|
||||
index_reduce := cast(uint)intrinsics.simd_reduce_min(index_select)
|
||||
return -1 if a[i+index_reduce] < b[i+index_reduce] else +1
|
||||
}
|
||||
}
|
||||
|
||||
for /**/; i < n; i += 1 {
|
||||
if a[i] ~ b[i] != 0 {
|
||||
return -1 if int(a[i]) - int(b[i]) < 0 else +1
|
||||
}
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
memory_compare_zero :: proc "contextless" (a: rawptr, n: int) -> int #no_bounds_check {
|
||||
x := uintptr(a)
|
||||
n := uintptr(n)
|
||||
n := uint(n)
|
||||
i := uint(0)
|
||||
m := uint(0)
|
||||
|
||||
SU :: size_of(uintptr)
|
||||
fast := n/SU + 1
|
||||
offset := (fast-1)*SU
|
||||
curr_block := uintptr(0)
|
||||
if n < SU {
|
||||
fast = 0
|
||||
// Because we're comparing against zero, we never return -1, as that would
|
||||
// indicate the compared value is less than zero.
|
||||
//
|
||||
// Note that a zero return value here means equality.
|
||||
|
||||
bytes := ([^]u8)(a)
|
||||
|
||||
if n >= 8 {
|
||||
when HAS_HARDWARE_SIMD {
|
||||
when ODIN_ARCH == .amd64 && intrinsics.has_target_feature("avx2") {
|
||||
scanner32: #simd[32]u8
|
||||
m = n / 32 * 32
|
||||
for /**/; i < m; i += 32 {
|
||||
load := intrinsics.unaligned_load(cast(^#simd[32]u8)&bytes[i])
|
||||
ne := intrinsics.simd_lanes_ne(scanner32, load)
|
||||
if intrinsics.simd_reduce_or(ne) > 0 {
|
||||
return 1
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
scanner16: #simd[16]u8
|
||||
m = (n-i) / 16 * 16
|
||||
for /**/; i < m; i += 16 {
|
||||
load := intrinsics.unaligned_load(cast(^#simd[16]u8)&bytes[i])
|
||||
ne := intrinsics.simd_lanes_ne(scanner16, load)
|
||||
if intrinsics.simd_reduce_or(ne) != 0 {
|
||||
return 1
|
||||
}
|
||||
}
|
||||
|
||||
m = (n-i) / 8 * 8
|
||||
for /**/; i < m; i += 8 {
|
||||
if intrinsics.unaligned_load(cast(^uintptr)&bytes[i]) != 0 {
|
||||
return 1
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for /**/; curr_block < fast; curr_block += 1 {
|
||||
va := (^uintptr)(x + curr_block * size_of(uintptr))^
|
||||
if va ~ 0 != 0 {
|
||||
for pos := curr_block*SU; pos < n; pos += 1 {
|
||||
a := (^byte)(x+pos)^
|
||||
if a ~ 0 != 0 {
|
||||
return -1 if int(a) < 0 else +1
|
||||
for /**/; i < n; i += 1 {
|
||||
if bytes[i] != 0 {
|
||||
return 1
|
||||
}
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
memory_prefix_length :: proc "contextless" (x, y: rawptr, n: int) -> (idx: int) #no_bounds_check {
|
||||
switch {
|
||||
case x == y: return n
|
||||
case x == nil: return 0
|
||||
case y == nil: return 0
|
||||
}
|
||||
a, b := cast([^]byte)x, cast([^]byte)y
|
||||
|
||||
n := uint(n)
|
||||
i := uint(0)
|
||||
m := uint(0)
|
||||
|
||||
when HAS_HARDWARE_SIMD {
|
||||
when ODIN_ARCH == .amd64 && intrinsics.has_target_feature("avx2") {
|
||||
m = n / 32 * 32
|
||||
for /**/; i < m; i += 32 {
|
||||
load_a := intrinsics.unaligned_load(cast(^#simd[32]u8)&a[i])
|
||||
load_b := intrinsics.unaligned_load(cast(^#simd[32]u8)&b[i])
|
||||
comparison := intrinsics.simd_lanes_ne(load_a, load_b)
|
||||
if intrinsics.simd_reduce_or(comparison) != 0 {
|
||||
sentinel: #simd[32]u8 = u8(0xFF)
|
||||
indices := intrinsics.simd_indices(#simd[32]u8)
|
||||
index_select := intrinsics.simd_select(comparison, indices, sentinel)
|
||||
index_reduce := cast(uint)intrinsics.simd_reduce_min(index_select)
|
||||
return int(i + index_reduce)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for /**/; offset < n; offset += 1 {
|
||||
a := (^byte)(x+offset)^
|
||||
if a ~ 0 != 0 {
|
||||
return -1 if int(a) < 0 else +1
|
||||
m = (n-i) / 16 * 16
|
||||
for /**/; i < m; i += 16 {
|
||||
load_a := intrinsics.unaligned_load(cast(^#simd[16]u8)&a[i])
|
||||
load_b := intrinsics.unaligned_load(cast(^#simd[16]u8)&b[i])
|
||||
comparison := intrinsics.simd_lanes_ne(load_a, load_b)
|
||||
if intrinsics.simd_reduce_or(comparison) != 0 {
|
||||
sentinel: #simd[16]u8 = u8(0xFF)
|
||||
indices := intrinsics.simd_indices(#simd[16]u8)
|
||||
index_select := intrinsics.simd_select(comparison, indices, sentinel)
|
||||
index_reduce := cast(uint)intrinsics.simd_reduce_min(index_select)
|
||||
return int(i + index_reduce)
|
||||
}
|
||||
}
|
||||
|
||||
return 0
|
||||
// 64-bit SIMD is faster than using a `uintptr` to detect a difference then
|
||||
// re-iterating with the byte-by-byte loop, at least on AMD64.
|
||||
m = (n-i) / 8 * 8
|
||||
for /**/; i < m; i += 8 {
|
||||
load_a := intrinsics.unaligned_load(cast(^#simd[8]u8)&a[i])
|
||||
load_b := intrinsics.unaligned_load(cast(^#simd[8]u8)&b[i])
|
||||
comparison := intrinsics.simd_lanes_ne(load_a, load_b)
|
||||
if intrinsics.simd_reduce_or(comparison) != 0 {
|
||||
sentinel: #simd[8]u8 = u8(0xFF)
|
||||
indices := intrinsics.simd_indices(#simd[8]u8)
|
||||
index_select := intrinsics.simd_select(comparison, indices, sentinel)
|
||||
index_reduce := cast(uint)intrinsics.simd_reduce_min(index_select)
|
||||
return int(i + index_reduce)
|
||||
}
|
||||
}
|
||||
|
||||
for /**/; i < n; i += 1 {
|
||||
if a[i] ~ b[i] != 0 {
|
||||
return int(i)
|
||||
}
|
||||
}
|
||||
return int(n)
|
||||
}
|
||||
|
||||
string_eq :: proc "contextless" (lhs, rhs: string) -> bool {
|
||||
|
||||
Reference in New Issue
Block a user