Merge branch 'master' into poly

This commit is contained in:
kalsprite
2026-08-07 17:41:30 -07:00
41 changed files with 1301 additions and 224 deletions

View File

@@ -1032,9 +1032,9 @@ quo_quaternion64 :: proc "contextless" (q, r: quaternion64) -> quaternion64 {
invmag2 := 1.0 / (r0*r0 + r1*r1 + r2*r2 + r3*r3)
t0 := (r0*q0 + r1*q1 + r2*q2 + r3*q3) * invmag2
t1 := (r0*q1 - r1*q0 - r2*q3 - r3*q2) * invmag2
t1 := (r0*q1 - r1*q0 + r2*q3 - r3*q2) * invmag2
t2 := (r0*q2 - r1*q3 - r2*q0 + r3*q1) * invmag2
t3 := (r0*q3 + r1*q2 + r2*q1 - r3*q0) * invmag2
t3 := (r0*q3 + r1*q2 - r2*q1 - r3*q0) * invmag2
return quaternion(w=f16(t0), x=f16(t1), y=f16(t2), z=f16(t3))
}
@@ -1046,9 +1046,9 @@ quo_quaternion128 :: proc "contextless" (q, r: quaternion128) -> quaternion128 {
invmag2 := 1.0 / (r0*r0 + r1*r1 + r2*r2 + r3*r3)
t0 := (r0*q0 + r1*q1 + r2*q2 + r3*q3) * invmag2
t1 := (r0*q1 - r1*q0 - r2*q3 - r3*q2) * invmag2
t1 := (r0*q1 - r1*q0 + r2*q3 - r3*q2) * invmag2
t2 := (r0*q2 - r1*q3 - r2*q0 + r3*q1) * invmag2
t3 := (r0*q3 + r1*q2 + r2*q1 - r3*q0) * invmag2
t3 := (r0*q3 + r1*q2 - r2*q1 - r3*q0) * invmag2
return quaternion(w=t0, x=t1, y=t2, z=t3)
}
@@ -1060,9 +1060,9 @@ quo_quaternion256 :: proc "contextless" (q, r: quaternion256) -> quaternion256 {
invmag2 := 1.0 / (r0*r0 + r1*r1 + r2*r2 + r3*r3)
t0 := (r0*q0 + r1*q1 + r2*q2 + r3*q3) * invmag2
t1 := (r0*q1 - r1*q0 - r2*q3 - r3*q2) * invmag2
t1 := (r0*q1 - r1*q0 + r2*q3 - r3*q2) * invmag2
t2 := (r0*q2 - r1*q3 - r2*q0 + r3*q1) * invmag2
t3 := (r0*q3 + r1*q2 + r2*q1 - r3*q0) * invmag2
t3 := (r0*q3 + r1*q2 - r2*q1 - r3*q0) * invmag2
return quaternion(w=t0, x=t1, y=t2, z=t3)
}

View File

@@ -23,7 +23,7 @@ chacha8rand_refill_ref :: proc(r: ^Default_Random_State) {
s8 := intrinsics.byte_swap(k[4])
s9 := intrinsics.byte_swap(k[5])
s10 := intrinsics.byte_swap(k[6])
s11 := intrinicss.byte_swap(k[7])
s11 := intrinsics.byte_swap(k[7])
}
s12: u32 // Counter starts at 0.
s13, s14, s15: u32 // IV of all 0s.

View File

@@ -1,5 +1,6 @@
package _chacha20
import "base:intrinsics"
import "core:crypto"
import "core:encoding/endian"
import "core:math/bits"
@@ -108,11 +109,16 @@ check_counter_limit :: proc(ctx: ^Context, nr_blocks: int) {
ctr_ok: bool
if ctx._is_ietf_flavor {
ctr_ok = u64(ctx._s[12]) + u64(nr_blocks) <= MAX_CTR_IETF
if intrinsics.unlikely(ctx._s[12] == MAX_CTR_IETF && nr_blocks > 1) {
// Allow the final block.
ctr_ok = false
} else {
ctr_ok = u64(ctx._s[12]) + u64(nr_blocks) <= MAX_CTR_IETF
}
} else {
ctr := (u64(ctx._s[13]) << 32) | u64(ctx._s[12])
_, carry := bits.add_u64(ctr, u64(nr_blocks), 0)
ctr_ok = carry == 0
new_ctr, carry := bits.add_u64(ctr, u64(nr_blocks), 0)
ctr_ok = carry == 0 || new_ctr != 0 // Allow the final block.
}
ensure(ctr_ok, "crypto/chacha20: maximum (X)ChaCha20 keystream per IV reached")

View File

@@ -35,6 +35,10 @@ sum :: proc(sec_strength: int, dst, msg, key, domain_sep: []byte) {
// strength, key and domain separator over msg and return true if and only if (⟺) the
// tag is valid.
verify :: proc(sec_strength: int, tag, msg, key, domain_sep: []byte, allocator := context.temp_allocator) -> bool {
if len(tag) < MIN_TAG_SIZE {
return false
}
derived_tag := make([]byte, len(tag), allocator)
defer(delete(derived_tag))

View File

@@ -269,7 +269,7 @@ params :: proc(k: ^$T) -> Parameters where (T == Encapsulation_Key || T == Decap
@(require_results)
key_size :: proc(k: ^$T) -> int where (T == Encapsulation_Key || T == Decapsulation_Key) {
when T == Encapsulation_Key {
return ENCAPSULATION_KEY_SIZES[k.pke_ek.k]
return ENCAPSULATION_KEY_SIZES[params(k)]
} else {
return DECAPSULATION_KEY_SEED_SIZE
}

View File

@@ -217,7 +217,7 @@ cipherstate_encrypt_with_ad :: proc(self: ^Cipher_State, ad, plaintext, dst: []b
}
_encrypt(&self.ctx, self.n, ad, plaintext, dst)
self.n += 1
if self.n == 0 {
if self.n == max(u64) {
self.n_exhausted = true
}
} else {
@@ -249,7 +249,7 @@ cipherstate_decrypt_with_ad :: proc(self: ^Cipher_State, ad, ciphertext, dst: []
return nil, status
}
self.n += 1
if self.n == 0 {
if self.n == max(u64) {
self.n_exhausted = true
}
} else {

View File

@@ -19,6 +19,8 @@ derive :: proc(
iterations: u32,
dst: []byte,
) {
ensure(iterations > 0, "crypto/pbkdf2: non-zero iterations required")
h_len := hash.DIGEST_SIZES[hmac_hash]
// 1. If dkLen > (2^32 - 1) * hLen, output "derived key too long"

View File

@@ -19,7 +19,6 @@ package net
*/
import "core:strings"
import "core:strconv"
import "core:unicode/utf8"
import "core:encoding/hex"
@@ -114,6 +113,8 @@ join_url :: proc(scheme, host, path: string, queries: map[string]string, fragmen
}
percent_encode :: proc(s: string, allocator := context.allocator) -> string {
HEX_DIGITS_UPPER := "0123456789ABCDEF" // NOTE(michtesar): RFC 3986 §2.1
b := strings.builder_make(allocator)
strings.builder_grow(&b, len(s) + 16) // NOTE(tetra): A reasonable number to allow for the number of things we need to escape.
@@ -124,10 +125,9 @@ percent_encode :: proc(s: string, allocator := context.allocator) -> string {
case:
bytes, n := utf8.encode_rune(ch)
for byte in bytes[:n] {
buf: [2]u8 = ---
t := strconv.write_int(buf[:], i64(byte), 16)
strings.write_rune(&b, '%')
strings.write_string(&b, t)
strings.write_byte(&b, '%')
strings.write_byte(&b, HEX_DIGITS_UPPER[byte >> 4])
strings.write_byte(&b, HEX_DIGITS_UPPER[byte & 0xF])
}
}
}

View File

@@ -84,7 +84,13 @@ _remove_all :: proc(path: string) -> Error {
}
temp_allocator := TEMP_ALLOCATOR_GUARD({})
dir := win32_utf8_to_wstring(path, temp_allocator) or_return
// SHFileOperationW is documented as not thread safe with relative paths.
abs_path := path
if !_is_absolute_path(path) {
abs_path = _get_absolute_path(path, temp_allocator) or_return
}
dir := win32_utf8_to_wstring(abs_path, temp_allocator) or_return
empty: [1]u16

596
core/simd/arm/neon.odin Normal file
View File

@@ -0,0 +1,596 @@
#+build arm64,arm32
package simd_arm
import "core:simd"
// Count leading sign bits.
//
// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vcls_s8)
@(require_results, enable_target_feature = "neon")
vcls_s8 :: #force_inline proc "c" (a: int8x8_t) -> int8x8_t {
return _vcls_s8(a)
}
// Count leading sign bits.
//
// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vcls_s16)
@(require_results, enable_target_feature = "neon")
vcls_s16 :: #force_inline proc "c" (a: int16x4_t) -> int16x4_t {
return _vcls_s16(a)
}
// Count leading sign bits.
//
// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vcls_s32)
@(require_results, enable_target_feature = "neon")
vcls_s32 :: #force_inline proc "c" (a: int32x2_t) -> int32x2_t {
return _vcls_s32(a)
}
// Count leading sign bits.
//
// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vcls_u8)
@(require_results, enable_target_feature = "neon")
vcls_u8 :: #force_inline proc "c" (a: uint8x8_t) -> int8x8_t {
return vcls_s8(transmute(int8x8_t)a)
}
// Count leading sign bits.
//
// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vcls_u16)
@(require_results, enable_target_feature = "neon")
vcls_u16 :: #force_inline proc "c" (a: uint16x4_t) -> int16x4_t {
return vcls_s16(transmute(int16x4_t)a)
}
// Count leading sign bits.
//
// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vcls_u32)
@(require_results, enable_target_feature = "neon")
vcls_u32 :: #force_inline proc "c" (a: uint32x2_t) -> int32x2_t {
return vcls_s32(transmute(int32x2_t)a)
}
// Count leading sign bits.
//
// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vclsq_s8)
@(require_results, enable_target_feature = "neon")
vclsq_s8 :: #force_inline proc "c" (a: int8x16_t) -> int8x16_t {
return _vclsq_s8(a)
}
// Count leading sign bits.
//
// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vclsq_s16)
@(require_results, enable_target_feature = "neon")
vclsq_s16 :: #force_inline proc "c" (a: int16x8_t) -> int16x8_t {
return _vclsq_s16(a)
}
// Count leading sign bits.
//
// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vclsq_s32)
@(require_results, enable_target_feature = "neon")
vclsq_s32 :: #force_inline proc "c" (a: int32x4_t) -> int32x4_t {
return _vclsq_s32(a)
}
// Count leading sign bits.
//
// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vclsq_u8)
@(require_results, enable_target_feature = "neon")
vclsq_u8 :: #force_inline proc "c" (a: uint8x16_t) -> int8x16_t {
return vclsq_s8(transmute(int8x16_t)a)
}
// Count leading sign bits.
//
// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vclsq_u16)
@(require_results, enable_target_feature = "neon")
vclsq_u16 :: #force_inline proc "c" (a: uint16x8_t) -> int16x8_t {
return vclsq_s16(transmute(int16x8_t)a)
}
// Count leading sign bits.
//
// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vclsq_u32)
@(require_results, enable_target_feature = "neon")
vclsq_u32 :: #force_inline proc "c" (a: uint32x4_t) -> int32x4_t {
return vclsq_s32(transmute(int32x4_t)a)
}
// Count leading zero bits.
//
// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vclz_s8)
@(require_results, enable_target_feature = "neon")
vclz_s8 :: #force_inline proc "c" (a: int8x8_t) -> int8x8_t {
return simd.count_leading_zeros(a)
}
// Count leading zero bits.
//
// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vclz_s16)
@(require_results, enable_target_feature = "neon")
vclz_s16 :: #force_inline proc "c" (a: int16x4_t) -> int16x4_t {
return simd.count_leading_zeros(a)
}
// Count leading zero bits.
//
// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vclz_s32)
@(require_results, enable_target_feature = "neon")
vclz_s32 :: #force_inline proc "c" (a: int32x2_t) -> int32x2_t {
return simd.count_leading_zeros(a)
}
// Count leading zero bits.
//
// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vclz_u8)
@(require_results, enable_target_feature = "neon")
vclz_u8 :: #force_inline proc "c" (a: uint8x8_t) -> uint8x8_t {
return transmute(uint8x8_t)vclz_s8(transmute(int8x8_t)a)
}
// Count leading zero bits.
//
// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vclz_u16)
@(require_results, enable_target_feature = "neon")
vclz_u16 :: #force_inline proc "c" (a: uint16x4_t) -> uint16x4_t {
return transmute(uint16x4_t)vclz_s16(transmute(int16x4_t)a)
}
// Count leading zero bits.
//
// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vclz_u32)
@(require_results, enable_target_feature = "neon")
vclz_u32 :: #force_inline proc "c" (a: uint32x2_t) -> uint32x2_t {
return transmute(uint32x2_t)vclz_s32(transmute(int32x2_t)a)
}
// Count leading zero bits.
//
// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vclzq_s8)
@(require_results, enable_target_feature = "neon")
vclzq_s8 :: #force_inline proc "c" (a: int8x16_t) -> int8x16_t {
return simd.count_leading_zeros(a)
}
// Count leading zero bits.
//
// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vclzq_s16)
@(require_results, enable_target_feature = "neon")
vclzq_s16 :: #force_inline proc "c" (a: int16x8_t) -> int16x8_t {
return simd.count_leading_zeros(a)
}
// Count leading zero bits.
//
// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vclzq_s32)
@(require_results, enable_target_feature = "neon")
vclzq_s32 :: #force_inline proc "c" (a: int32x4_t) -> int32x4_t {
return simd.count_leading_zeros(a)
}
// Count leading zero bits.
//
// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vclzq_u8)
@(require_results, enable_target_feature = "neon")
vclzq_u8 :: #force_inline proc "c" (a: uint8x16_t) -> uint8x16_t {
return transmute(uint8x16_t)vclzq_s8(transmute(int8x16_t)a)
}
// Count leading zero bits.
//
// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vclzq_u16)
@(require_results, enable_target_feature = "neon")
vclzq_u16 :: #force_inline proc "c" (a: uint16x8_t) -> uint16x8_t {
return transmute(uint16x8_t)vclzq_s16(transmute(int16x8_t)a)
}
// Count leading zero bits.
//
// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vclzq_u32)
@(require_results, enable_target_feature = "neon")
vclzq_u32 :: #force_inline proc "c" (a: uint32x4_t) -> uint32x4_t {
return transmute(uint32x4_t)vclzq_s32(transmute(int32x4_t)a)
}
// Population count per byte.
//
// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vcnt_s8)
@(require_results, enable_target_feature = "neon")
vcnt_s8 :: #force_inline proc "c" (a: int8x8_t) -> int8x8_t {
return simd.count_ones(a)
}
// Population count per byte.
//
// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vcnt_u8)
@(require_results, enable_target_feature = "neon")
vcnt_u8 :: #force_inline proc "c" (a: uint8x8_t) -> uint8x8_t {
return transmute(uint8x8_t)vcnt_s8(transmute(int8x8_t)a)
}
// Population count per byte.
//
// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vcnt_p8)
@(require_results, enable_target_feature = "neon")
vcnt_p8 :: #force_inline proc "c" (a: poly8x8_t) -> poly8x8_t {
return transmute(poly8x8_t)vcnt_s8(transmute(int8x8_t)a)
}
// Population count per byte.
//
// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vcntq_s8)
@(require_results, enable_target_feature = "neon")
vcntq_s8 :: #force_inline proc "c" (a: int8x16_t) -> int8x16_t {
return simd.count_ones(a)
}
// Population count per byte.
//
// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vcntq_u8)
@(require_results, enable_target_feature = "neon")
vcntq_u8 :: #force_inline proc "c" (a: uint8x16_t) -> uint8x16_t {
return transmute(uint8x16_t)vcntq_s8(transmute(int8x16_t)a)
}
// Population count per byte.
//
// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vcntq_p8)
@(require_results, enable_target_feature = "neon")
vcntq_p8 :: #force_inline proc "c" (a: poly8x16_t) -> poly8x16_t {
return transmute(poly8x16_t)vcntq_s8(transmute(int8x16_t)a)
}
// Vector bitwise bit clear.
//
// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vbic_s8)
@(require_results, enable_target_feature = "neon")
vbic_s8 :: #force_inline proc "c" (a: int8x8_t, b: int8x8_t) -> int8x8_t {
c := int8x8_t(-1)
return simd.bit_and(simd.bit_xor(b, c), a)
}
// Vector bitwise bit clear.
//
// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vbic_s16)
@(require_results, enable_target_feature = "neon")
vbic_s16 :: #force_inline proc "c" (a: int16x4_t, b: int16x4_t) -> int16x4_t {
c := int16x4_t(-1)
return simd.bit_and(simd.bit_xor(b, c), a)
}
// Vector bitwise bit clear.
//
// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vbic_s32)
@(require_results, enable_target_feature = "neon")
vbic_s32 :: #force_inline proc "c" (a: int32x2_t, b: int32x2_t) -> int32x2_t {
c := int32x2_t(-1)
return simd.bit_and(simd.bit_xor(b, c), a)
}
// Vector bitwise bit clear.
//
// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vbic_s64)
@(require_results, enable_target_feature = "neon")
vbic_s64 :: #force_inline proc "c" (a: int64x1_t, b: int64x1_t) -> int64x1_t {
c := int64x1_t(-1)
return simd.bit_and(simd.bit_xor(b, c), a)
}
// Vector bitwise bit clear.
//
// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vbic_u8)
@(require_results, enable_target_feature = "neon")
vbic_u8 :: #force_inline proc "c" (a: uint8x8_t, b: uint8x8_t) -> uint8x8_t {
c := int8x8_t(-1)
return simd.bit_and(simd.bit_xor(b, transmute(uint8x8_t)c), a)
}
// Vector bitwise bit clear.
//
// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vbic_u16)
@(require_results, enable_target_feature = "neon")
vbic_u16 :: #force_inline proc "c" (a: uint16x4_t, b: uint16x4_t) -> uint16x4_t {
c := int16x4_t(-1)
return simd.bit_and(simd.bit_xor(b, transmute(uint16x4_t)c), a)
}
// Vector bitwise bit clear.
//
// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vbic_u32)
@(require_results, enable_target_feature = "neon")
vbic_u32 :: #force_inline proc "c" (a: uint32x2_t, b: uint32x2_t) -> uint32x2_t {
c := int32x2_t(-1)
return simd.bit_and(simd.bit_xor(b, transmute(uint32x2_t)c), a)
}
// Vector bitwise bit clear.
//
// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vbic_u64)
@(require_results, enable_target_feature = "neon")
vbic_u64 :: #force_inline proc "c" (a: uint64x1_t, b: uint64x1_t) -> uint64x1_t {
c := int64x1_t(-1)
return simd.bit_and(simd.bit_xor(b, transmute(uint64x1_t)c), a)
}
// Vector bitwise bit clear.
//
// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vbicq_s8)
@(require_results, enable_target_feature = "neon")
vbicq_s8 :: #force_inline proc "c" (a: int8x16_t, b: int8x16_t) -> int8x16_t {
c := int8x16_t(-1)
return simd.bit_and(simd.bit_xor(b, c), a)
}
// Vector bitwise bit clear.
//
// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vbicq_s16)
@(require_results, enable_target_feature = "neon")
vbicq_s16 :: #force_inline proc "c" (a: int16x8_t, b: int16x8_t) -> int16x8_t {
c := int16x8_t(-1)
return simd.bit_and(simd.bit_xor(b, c), a)
}
// Vector bitwise bit clear.
//
// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vbicq_s32)
@(require_results, enable_target_feature = "neon")
vbicq_s32 :: #force_inline proc "c" (a: int32x4_t, b: int32x4_t) -> int32x4_t {
c := int32x4_t(-1)
return simd.bit_and(simd.bit_xor(b, c), a)
}
// Vector bitwise bit clear.
//
// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vbicq_s64)
@(require_results, enable_target_feature = "neon")
vbicq_s64 :: #force_inline proc "c" (a: int64x2_t, b: int64x2_t) -> int64x2_t {
c := int64x2_t(-1)
return simd.bit_and(simd.bit_xor(b, c), a)
}
// Vector bitwise bit clear.
//
// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vbicq_u8)
@(require_results, enable_target_feature = "neon")
vbicq_u8 :: #force_inline proc "c" (a: uint8x16_t, b: uint8x16_t) -> uint8x16_t {
c := int8x16_t(-1)
return simd.bit_and(simd.bit_xor(b, transmute(uint8x16_t)c), a)
}
// Vector bitwise bit clear.
//
// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vbicq_u16)
@(require_results, enable_target_feature = "neon")
vbicq_u16 :: #force_inline proc "c" (a: uint16x8_t, b: uint16x8_t) -> uint16x8_t {
c := int16x8_t(-1)
return simd.bit_and(simd.bit_xor(b, transmute(uint16x8_t)c), a)
}
// Vector bitwise bit clear.
//
// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vbicq_u32)
@(require_results, enable_target_feature = "neon")
vbicq_u32 :: #force_inline proc "c" (a: uint32x4_t, b: uint32x4_t) -> uint32x4_t {
c := int32x4_t(-1)
return simd.bit_and(simd.bit_xor(b, transmute(uint32x4_t)c), a)
}
// Vector bitwise bit clear.
//
// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vbicq_u64)
@(require_results, enable_target_feature = "neon")
vbicq_u64 :: #force_inline proc "c" (a: uint64x2_t, b: uint64x2_t) -> uint64x2_t {
c := int64x2_t(-1)
return simd.bit_and(simd.bit_xor(b, transmute(uint64x2_t)c), a)
}
// Bitwise Select.
//
// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vbsl_s8)
@(require_results, enable_target_feature = "neon")
vbsl_s8 :: #force_inline proc "c" (a: uint8x8_t, b: int8x8_t, c: int8x8_t) -> int8x8_t {
not := int8x8_t(-1)
return transmute(int8x8_t)simd.bit_or(
simd.bit_and(a, transmute(uint8x8_t)b),
simd.bit_and(simd.bit_xor(a, transmute(uint8x8_t)not), transmute(uint8x8_t)c),
)
}
// Bitwise Select.
//
// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vbsl_s16)
@(require_results, enable_target_feature = "neon")
vbsl_s16 :: #force_inline proc "c" (a: uint16x4_t, b: int16x4_t, c: int16x4_t) -> int16x4_t {
not := int16x4_t(-1)
return transmute(int16x4_t)simd.bit_or(
simd.bit_and(a, transmute(uint16x4_t)b),
simd.bit_and(simd.bit_xor(a, transmute(uint16x4_t)not), transmute(uint16x4_t)c),
)
}
// Bitwise Select.
//
// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vbsl_s32)
@(require_results, enable_target_feature = "neon")
vbsl_s32 :: #force_inline proc "c" (a: uint32x2_t, b: int32x2_t, c: int32x2_t) -> int32x2_t {
not := int32x2_t(-1)
return transmute(int32x2_t)simd.bit_or(
simd.bit_and(a, transmute(uint32x2_t)b),
simd.bit_and(simd.bit_xor(a, transmute(uint32x2_t)not), transmute(uint32x2_t)c),
)
}
// Bitwise Select.
//
// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vbsl_s64)
@(require_results, enable_target_feature = "neon")
vbsl_s64 :: #force_inline proc "c" (a: uint64x1_t, b: int64x1_t, c: int64x1_t) -> int64x1_t {
not := int64x1_t(-1)
return transmute(int64x1_t)simd.bit_or(
simd.bit_and(a, transmute(uint64x1_t)b),
simd.bit_and(simd.bit_xor(a, transmute(uint64x1_t)not), transmute(uint64x1_t)c),
)
}
// Bitwise Select.
//
// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vbsl_u8)
@(require_results, enable_target_feature = "neon")
vbsl_u8 :: #force_inline proc "c" (a: uint8x8_t, b: uint8x8_t, c: uint8x8_t) -> uint8x8_t {
not := int8x8_t(-1)
return simd.bit_or(
simd.bit_and(a, b),
simd.bit_and(simd.bit_xor(a, transmute(uint8x8_t)not), c),
)
}
// Bitwise Select.
//
// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vbsl_u16)
@(require_results, enable_target_feature = "neon")
vbsl_u16 :: #force_inline proc "c" (a: uint16x4_t, b: uint16x4_t, c: uint16x4_t) -> uint16x4_t {
not := int16x4_t(-1)
return simd.bit_or(
simd.bit_and(a, b),
simd.bit_and(simd.bit_xor(a, transmute(uint16x4_t)not), c),
)
}
// Bitwise Select.
//
// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vbsl_u32)
@(require_results, enable_target_feature = "neon")
vbsl_u32 :: #force_inline proc "c" (a: uint32x2_t, b: uint32x2_t, c: uint32x2_t) -> uint32x2_t {
not := int32x2_t(-1)
return simd.bit_or(
simd.bit_and(a, b),
simd.bit_and(simd.bit_xor(a, transmute(uint32x2_t)not), c),
)
}
// Bitwise Select.
//
// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vbsl_u64)
@(require_results, enable_target_feature = "neon")
vbsl_u64 :: #force_inline proc "c" (a: uint64x1_t, b: uint64x1_t, c: uint64x1_t) -> uint64x1_t {
not := int64x1_t(-1)
return simd.bit_or(
simd.bit_and(a, b),
simd.bit_and(simd.bit_xor(a, transmute(uint64x1_t)not), c),
)
}
// Bitwise Select.
//
// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vbslq_s8)
@(require_results, enable_target_feature = "neon")
vbslq_s8 :: #force_inline proc "c" (a: uint8x16_t, b: int8x16_t, c: int8x16_t) -> int8x16_t {
not := int8x16_t(-1)
return transmute(int8x16_t)simd.bit_or(
simd.bit_and(a, transmute(uint8x16_t)b),
simd.bit_and(simd.bit_xor(a, transmute(uint8x16_t)not), transmute(uint8x16_t)c),
)
}
// Bitwise Select.
//
// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vbslq_s16)
@(require_results, enable_target_feature = "neon")
vbslq_s16 :: #force_inline proc "c" (a: uint16x8_t, b: int16x8_t, c: int16x8_t) -> int16x8_t {
not := int16x8_t(-1)
return transmute(int16x8_t)simd.bit_or(
simd.bit_and(a, transmute(uint16x8_t)b),
simd.bit_and(simd.bit_xor(a, transmute(uint16x8_t)not), transmute(uint16x8_t)c),
)
}
// Bitwise Select.
//
// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vbslq_s32)
@(require_results, enable_target_feature = "neon")
vbslq_s32 :: #force_inline proc "c" (a: uint32x4_t, b: int32x4_t, c: int32x4_t) -> int32x4_t {
not := int32x4_t(-1)
return transmute(int32x4_t)simd.bit_or(
simd.bit_and(a, transmute(uint32x4_t)b),
simd.bit_and(simd.bit_xor(a, transmute(uint32x4_t)not), transmute(uint32x4_t)c),
)
}
// Bitwise Select.
//
// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vbslq_s64)
@(require_results, enable_target_feature = "neon")
vbslq_s64 :: #force_inline proc "c" (a: uint64x2_t, b: int64x2_t, c: int64x2_t) -> int64x2_t {
not := int64x2_t(-1)
return transmute(int64x2_t)simd.bit_or(
simd.bit_and(a, transmute(uint64x2_t)b),
simd.bit_and(simd.bit_xor(a, transmute(uint64x2_t)not), transmute(uint64x2_t)c),
)
}
// Bitwise Select.
//
// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vbslq_u8)
@(require_results, enable_target_feature = "neon")
vbslq_u8 :: #force_inline proc "c" (a: uint8x16_t, b: uint8x16_t, c: uint8x16_t) -> uint8x16_t {
not := int8x16_t(-1)
return simd.bit_or(
simd.bit_and(a, b),
simd.bit_and(simd.bit_xor(a, transmute(uint8x16_t)not), c),
)
}
// Bitwise Select.
//
// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vbslq_u16)
@(require_results, enable_target_feature = "neon")
vbslq_u16 :: #force_inline proc "c" (a: uint16x8_t, b: uint16x8_t, c: uint16x8_t) -> uint16x8_t {
not := int16x8_t(-1)
return simd.bit_or(
simd.bit_and(a, b),
simd.bit_and(simd.bit_xor(a, transmute(uint16x8_t)not), c),
)
}
// Bitwise Select.
//
// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vbslq_u32)
@(require_results, enable_target_feature = "neon")
vbslq_u32 :: #force_inline proc "c" (a: uint32x4_t, b: uint32x4_t, c: uint32x4_t) -> uint32x4_t {
not := int32x4_t(-1)
return simd.bit_or(
simd.bit_and(a, b),
simd.bit_and(simd.bit_xor(a, transmute(uint32x4_t)not), c),
)
}
// Bitwise Select.
//
// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vbslq_u64)
@(require_results, enable_target_feature = "neon")
vbslq_u64 :: #force_inline proc "c" (a: uint64x2_t, b: uint64x2_t, c: uint64x2_t) -> uint64x2_t {
not := int64x2_t(-1)
return simd.bit_or(
simd.bit_and(a, b),
simd.bit_and(simd.bit_xor(a, transmute(uint64x2_t)not), c),
)
}
@(private, default_calling_convention = "none")
foreign _ {
@(link_name = "llvm.aarch64.neon.cls.v8i8" when ODIN_ARCH == .arm64 else "llvm.arm.neon.vcls.v8i8")
_vcls_s8 :: proc(a: int8x8_t) -> int8x8_t ---
@(link_name = "llvm.aarch64.neon.cls.v4i16" when ODIN_ARCH == .arm64 else "llvm.arm.neon.vcls.v4i16")
_vcls_s16 :: proc(a: int16x4_t) -> int16x4_t ---
@(link_name = "llvm.aarch64.neon.cls.v2i32" when ODIN_ARCH == .arm64 else "llvm.arm.neon.vcls.v2i32")
_vcls_s32 :: proc(a: int32x2_t) -> int32x2_t ---
@(link_name = "llvm.aarch64.neon.cls.v16i8" when ODIN_ARCH == .arm64 else "llvm.arm.neon.vcls.v16i8")
_vclsq_s8 :: proc(a: int8x16_t) -> int8x16_t ---
@(link_name = "llvm.aarch64.neon.cls.v8i16" when ODIN_ARCH == .arm64 else "llvm.arm.neon.vcls.v8i16")
_vclsq_s16 :: proc(a: int16x8_t) -> int16x8_t ---
@(link_name = "llvm.aarch64.neon.cls.v4i32" when ODIN_ARCH == .arm64 else "llvm.arm.neon.vcls.v4i32")
_vclsq_s32 :: proc(a: int32x4_t) -> int32x4_t ---
}

View File

@@ -3,6 +3,78 @@ package simd_arm
import "core:simd"
// Bitwise Select.
//
// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vbsl_p8)
@(require_results, enable_target_feature = "neon")
vbsl_p8 :: #force_inline proc "c" (a: uint8x8_t, b: poly8x8_t, c: poly8x8_t) -> poly8x8_t {
not := int8x8_t(-1)
return simd.bit_or(
simd.bit_and(a, b),
simd.bit_and(simd.bit_xor(a, transmute(uint8x8_t)not), c),
)
}
// Bitwise Select.
//
// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vbsl_p16)
@(require_results, enable_target_feature = "neon")
vbsl_p16 :: #force_inline proc "c" (a: uint16x4_t, b: poly16x4_t, c: poly16x4_t) -> poly16x4_t {
not := int16x4_t(-1)
return simd.bit_or(
simd.bit_and(a, b),
simd.bit_and(simd.bit_xor(a, transmute(uint16x4_t)not), c),
)
}
// Bitwise Select.
//
// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vbsl_p64)
@(require_results, enable_target_feature = "neon")
vbsl_p64 :: #force_inline proc "c" (a: poly64x1_t, b: poly64x1_t, c: poly64x1_t) -> poly64x1_t {
not := int64x1_t(-1)
return simd.bit_or(
simd.bit_and(a, b),
simd.bit_and(simd.bit_xor(a, transmute(poly64x1_t)not), c),
)
}
// Bitwise Select.
//
// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vbslq_p8)
@(require_results, enable_target_feature = "neon")
vbslq_p8 :: #force_inline proc "c" (a: uint8x16_t, b: poly8x16_t, c: poly8x16_t) -> poly8x16_t {
not := int8x16_t(-1)
return simd.bit_or(
simd.bit_and(a, b),
simd.bit_and(simd.bit_xor(a, transmute(poly8x16_t)not), c),
)
}
// Bitwise Select.
//
// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vbslq_p16)
@(require_results, enable_target_feature = "neon")
vbslq_p16 :: #force_inline proc "c" (a: uint16x8_t, b: poly16x8_t, c: poly16x8_t) -> poly16x8_t {
not := int16x8_t(-1)
return simd.bit_or(
simd.bit_and(a, b),
simd.bit_and(simd.bit_xor(a, transmute(poly16x8_t)not), c),
)
}
// Bitwise Select.
//
// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vbslq_p64)
@(require_results, enable_target_feature = "neon")
vbslq_p64 :: #force_inline proc "c" (a: poly64x2_t, b: poly64x2_t, c: poly64x2_t) -> poly64x2_t {
not := int64x2_t(-1)
return simd.bit_or(
simd.bit_and(a, b),
simd.bit_and(simd.bit_xor(a, transmute(poly64x2_t)not), c),
)
}
// Join two smaller vectors into a single larger vector
//
// [Arm's documentation](https://developer.arm.com/architectures/instruction-sets/intrinsics/vcombine_p8)

View File

@@ -2,6 +2,11 @@
package simd_arm
// Type aliases to match `arm_neon.h`.
int8_t :: i8
int16_t :: i16
int32_t :: i32
int64_t :: i64
uint8_t :: u8
uint16_t :: u16
uint32_t :: u32
@@ -12,12 +17,23 @@ poly16_t :: u16
poly64_t :: u64
poly128_t :: u128
uint8x16_t :: #simd[16]u8
uint32x4_t :: #simd[4]u32
uint64x2_t :: #simd[2]u64
int8x8_t :: #simd[8]int8_t
int8x16_t :: #simd[16]int8_t
int16x4_t :: #simd[4]int16_t
int16x8_t :: #simd[8]int16_t
int32x2_t :: #simd[2]int32_t
int32x4_t :: #simd[4]int32_t
int64x1_t :: #simd[1]int64_t
int64x2_t :: #simd[2]int64_t
int32_t :: i32
int8x16_t :: #simd[16]i8
uint8x8_t :: #simd[8]uint8_t
uint8x16_t :: #simd[16]uint8_t
uint16x4_t :: #simd[4]uint16_t
uint16x8_t :: #simd[8]uint16_t
uint32x2_t :: #simd[2]uint32_t
uint32x4_t :: #simd[4]uint32_t
uint64x1_t :: #simd[1]uint64_t
uint64x2_t :: #simd[2]uint64_t
poly8x8_t :: #simd[8]poly8_t
poly8x16_t :: #simd[16]poly8_t

View File

@@ -2,7 +2,7 @@
Cross-platform `SIMD` support types and procedures.
SIMD (Single Instruction Multiple Data), is a CPU hardware feature that
introduce special registers and instructions which operate on multiple units
introduces special registers and instructions which operate on multiple units
of data at the same time, which enables faster data processing for
applications with heavy computational workloads.

View File

@@ -187,6 +187,9 @@ pool_join :: proc(pool: ^Pool) {
//
// Each task also needs an allocator which it either owns, or which is thread
// safe.
//
// Completed tasks remain in the pool until removed with `pool_pop_done`.
// When reusing the pool, call it once for every task added.
pool_add_task :: proc(pool: ^Pool, allocator: mem.Allocator, procedure: Task_Proc, data: rawptr, user_index: int = 0) {
sync.guard(&pool.mutex)
@@ -344,7 +347,10 @@ pool_pop_waiting :: proc(pool: ^Pool) -> (task: Task, got_task: bool) {
return
}
// Use this to take out finished tasks.
// Remove and return the next completed task, if one is available.
//
// The caller is responsible for processing the result and releasing any
// resources associated with the task.
pool_pop_done :: proc(pool: ^Pool) -> (task: Task, got_task: bool) {
sync.guard(&pool.mutex)
@@ -374,6 +380,9 @@ pool_do_work :: proc(pool: ^Pool, task: Task) {
// Process the rest of the tasks, also use this thread for processing, then join
// all the pool threads.
//
// Completed tasks are not removed. Retrieve each one with `pool_pop_done`.
// The pool cannot be restarted after this procedure returns.
pool_finish :: proc(pool: ^Pool) {
for task in pool_pop_waiting(pool) {
pool_do_work(pool, task)

View File

@@ -54,6 +54,9 @@ Grapheme_Iterator :: struct {
current_sequence: Grapheme_Cluster_Sequence,
continue_sequence: bool,
current_grapheme: Grapheme,
continue_grapheme: bool,
}
@@ -147,13 +150,13 @@ decode_grapheme_iterate :: proc(it: ^Grapheme_Iterator) -> (text: string, graphe
if it.grapheme_count > it.last_grapheme_count {
it.width += normalized_east_asian_width(this_rune)
grapheme = Grapheme{
byte_index,
it.rune_count,
it.width - it.last_width,
if it.continue_grapheme {
grapheme = it.current_grapheme
text = it.str[it.current_grapheme.byte_index:byte_index]
ok = true
}
text = it.str[byte_index:][:grapheme.width]
ok = true
it.current_grapheme = Grapheme{byte_index, it.rune_count, it.width - it.last_width}
it.continue_grapheme = true
it.last_grapheme_count = it.grapheme_count
@@ -385,5 +388,14 @@ decode_grapheme_iterate :: proc(it: ^Grapheme_Iterator) -> (text: string, graphe
it.grapheme_count += 1
}
// Flush the remaining grapheme - the loop only flushes when
// a new grapheme is encountered.
if !ok && it.continue_grapheme {
grapheme = it.current_grapheme
text = it.str[it.current_grapheme.byte_index:]
ok = true
it.continue_grapheme = false
}
return
}
}

View File

@@ -694,7 +694,9 @@ gb_internal String big_int_to_string(gbAllocator allocator, BigInt const *x, u64
big_int_dealloc(&r);
big_int_dealloc(&b);
for (isize i = first_word_idx; i < buf.count/2; i++) {
// NOTE: only the digits are reversed, not the leading '-'.
isize digit_count = buf.count - first_word_idx;
for (isize i = first_word_idx; i < first_word_idx + digit_count/2; i++) {
isize j = buf.count + first_word_idx - i - 1;
char tmp = buf[i];
buf[i] = buf[j];

View File

@@ -410,6 +410,15 @@ gb_internal bool find_or_generate_polymorphic_procedure(CheckerContext *old_c, E
}
if (!src->Proc.is_polymorphic || src->Proc.is_poly_specialized) {
// NOTE: polymorphic procedure check not idempotent without this
if (src->Proc.is_poly_specialized && base_entity->Procedure.generated_from_polymorphic) {
if (are_types_identical(src, dst)) {
if (poly_proc_data) {
poly_proc_data->gen_entity = base_entity;
}
return true;
}
}
return false;
}
@@ -457,9 +466,7 @@ gb_internal bool find_or_generate_polymorphic_procedure(CheckerContext *old_c, E
scope->flags |= ScopeFlag_Proc;
nctx.scope = scope;
nctx.allow_polymorphic_types = true;
if (nctx.polymorphic_scope == nullptr) {
nctx.polymorphic_scope = scope;
}
nctx.polymorphic_scope = scope;
auto *pt = &src->Proc;
@@ -1027,17 +1034,6 @@ gb_internal bool check_is_assignable_to_with_score(CheckerContext *c, Operand *o
return false;
}
// Handle polymorphic procedure used as default parameter
if (operand->mode == Addressing_Value && is_type_proc(type) && is_type_proc(operand->type)) {
Entity *e = entity_from_expr(operand->expr);
if (e != nullptr && e->kind == Entity_Procedure && is_type_polymorphic(e->type) && !is_type_polymorphic(type)) {
// Special case: Allow a polymorphic procedure to be used as default value for concrete proc type
// during the initial check. It will be properly instantiated when actually used.
if (score_) *score_ = assign_score_function(1);
return true;
}
}
i64 score = check_distance_between_types(c, operand, type, allow_array_programming);
if (score >= 0) {
if (score_) *score_ = assign_score_function(score, is_variadic);
@@ -4090,7 +4086,7 @@ gb_internal bool check_transmute(CheckerContext *c, Ast *node, Operand *o, Type
big_int_shl_eq(&umax, &sz_in_bits);
if (is_type_unsigned(src_t) && !is_type_unsigned(dst_t)) {
if (big_int_cmp(&v, &smax) >= 0) {
if (big_int_cmp(&v, &smax) > 0) {
big_int_sub_eq(&v, &umax);
}
} else if (!is_type_unsigned(src_t) && is_type_unsigned(dst_t)) {
@@ -7637,7 +7633,9 @@ gb_internal CallArgumentData check_call_arguments_proc_group(CheckerContext *c,
if (max_matched_features > 0) {
for_array(i, valids) {
Entity *p = procs[valids[i].index];
// NOTE: A polymorphic candidate appends its instantiated entity to proc_entities above,
// so valids[i].index can be >= procs.count.
Entity *p = proc_entities[valids[i].index];
Type *t = base_type(p->type);
GB_ASSERT(t->kind == Type_Proc);

View File

@@ -1791,6 +1791,7 @@ gb_internal ParameterValue handle_parameter_value(CheckerContext *ctx, Type *in_
if (e->kind == Entity_Procedure) {
param_value.kind = ParameterValue_Constant;
param_value.value = exact_value_procedure(e->identifier);
param_value.proc_entity = e;
add_entity_use(ctx, e->identifier, e);
} else {
if (e->flags & EntityFlag_Param) {
@@ -2143,8 +2144,12 @@ gb_internal Type *check_get_params(CheckerContext *ctx, Scope *scope, Ast *_para
// This is just to add the error message to determine_type_from_polymorphic which
// depends on valid position information
op.expr = _params;
op.mode = Addressing_Invalid;
op.type = t_invalid;
// NOTE(taylbr): Can still have valid type with null expr. Needed for resolving
if (op.mode == Addressing_Invalid || op.type == nullptr) {
op.mode = Addressing_Invalid;
op.type = t_invalid;
}
}
if (is_type_polymorphic_type) {
type = determine_type_from_polymorphic(ctx, type, op);
@@ -2841,9 +2846,14 @@ gb_internal i64 check_array_count(CheckerContext *ctx, Operand *o, Ast *e) {
}
Type *type = core_type(o->type);
if (is_type_untyped(type) || is_type_integer(type)) {
if (o->value.kind == ExactValue_Integer) {
BigInt count = o->value.value_integer;
if (big_int_is_neg(&o->value.value_integer)) {
ExactValue value = o->value;
if (value.kind == ExactValue_Float) {
// NOTE: an integral float is a valid count, but it must be range checked as an integer
value = exact_value_to_integer(value);
}
if (value.kind == ExactValue_Integer) {
BigInt count = value.value_integer;
if (big_int_is_neg(&count)) {
gbAllocator a = heap_allocator();
String str = big_int_to_string(a, &count);
error(e, "Invalid negative array count, %.*s", LIT(str));
@@ -2859,12 +2869,6 @@ gb_internal i64 check_array_count(CheckerContext *ctx, Operand *o, Ast *e) {
error(e, "Array count too large, %.*s", LIT(str));
gb_free(a, str.text);
return 0;
} else if (o->value.kind == ExactValue_Float) {
u64 u = cast(u64)o->value.value_float;
f64 f = cast(f64)u;
if (f == o->value.value_float) {
return u;
}
}
}

View File

@@ -2050,18 +2050,26 @@ gb_internal bool redeclaration_error(String name, Entity *prev, Entity *found) {
// NOTE(bill): Error should have been handled already
return false;
}
// NOTE: the insertion order is a race between the files of a package, so order the pair by
// position; the later declaration stays the anchor, as it is the one being reported
TokenPos first = prev->token.pos;
TokenPos second = pos;
if (second < first) {
first = pos;
second = prev->token.pos;
}
if (found->flags & EntityFlag_Result) {
error(prev->token,
error(second,
"Direct shadowing of the named return value '%.*s' in this scope\n"
"\tat %s",
LIT(name),
token_pos_to_string(pos));
token_pos_to_string(first));
} else {
error(prev->token,
error(second,
"Redeclaration of '%.*s' in this scope\n"
"\tat %s",
LIT(name),
token_pos_to_string(pos));
token_pos_to_string(first));
}
}
return false;

View File

@@ -265,8 +265,12 @@ gb_internal OdinDocPosition odin_doc_token_pos_cast(OdinDocWriter *w, TokenPos c
AstFile *file = global_files[pos.file_id];
if (file != nullptr) {
OdinDocFileIndex *file_index_found = map_get(&w->file_cache, file);
GB_ASSERT(file_index_found != nullptr);
file_index = *file_index_found;
// NOTE: a documented entity may hold a position in a file belonging to an
// imported package. Such files are only in file_cache when -all-packages is
// used, so fall back to the reserved "no file" index.
if (file_index_found != nullptr) {
file_index = *file_index_found;
}
}
}

View File

@@ -111,6 +111,7 @@ enum ParameterValueKind {
struct ParameterValue {
ParameterValueKind kind;
Ast *original_ast_expr;
Entity *proc_entity;
union {
ExactValue value;
Ast *ast_value;

View File

@@ -419,6 +419,12 @@ gb_internal ExactValue exact_value_to_integer(ExactValue v) {
case ExactValue_Integer:
return v;
case ExactValue_Float: {
f64 const min = cast(f64)I64_MIN; // -2^63
f64 const max = -min; // 2^63, one past I64_MAX
// NOTE: the conversion below is undefined outside of this range, NaN included
if (!(v.value_float >= min && v.value_float < max)) {
break;
}
i64 i = cast(i64)v.value_float;
f64 f = cast(f64)i;
if (f == v.value_float) {

View File

@@ -155,7 +155,7 @@ try_cross_linking:;
String section_name = str_lit("msvc-link");
bool is_windows = build_context.metrics.os == TargetOs_windows;
#else
String section_name = str_lit("lld-link");
String section_name = str_lit("ld-link");
bool is_windows = false;
#endif

View File

@@ -1700,7 +1700,7 @@ gb_internal lbValue lb_const_value(lbModule *m, Type *type, ExactValue value, Ty
}
}
res.value = lb_build_constant_array_values(m, type, elem_type, cast(isize)type->Array.count, values, cc);
res.value = lb_build_constant_array_values(m, type, elem_type, cast(isize)type->EnumeratedArray.count, values, cc);
return res;
}
} else if (is_type_fixed_capacity_dynamic_array(type)) {

View File

@@ -4924,6 +4924,11 @@ gb_internal void lb_build_addr_compound_lit_populate(lbProcedure *p, Slice<Ast *
case Type_SimdVector: et = bt->SimdVector.elem; break;
case Type_Matrix: et = bt->Matrix.elem; break;
case Type_FixedCapacityDynamicArray: et = bt->FixedCapacityDynamicArray.elem; break;
case Type_Struct:
if (bt->Struct.soa_kind == StructSoa_Fixed) {
et = bt->Struct.soa_elem;
}
break;
}
GB_ASSERT(et != nullptr);
@@ -5038,18 +5043,17 @@ gb_internal void lb_build_addr_compound_lit_populate(lbProcedure *p, Slice<Ast *
}
gb_internal void lb_build_addr_compound_lit_assign_array(lbProcedure *p, Array<lbCompoundLitElemTempData> const &temp_data) {
for (auto const &td : temp_data) {
if (td.value.value != nullptr) {
if (td.elem_length > 0) {
auto loop_data = lb_loop_start(p, cast(isize)td.elem_length, t_i32);
{
lbValue dst = td.gep;
dst = lb_emit_ptr_offset(p, dst, loop_data.idx);
lb_emit_store(p, dst, td.value);
}
lb_loop_end(p, loop_data);
} else {
lb_emit_store(p, td.gep, td.value);
GB_ASSERT(td.value.value != nullptr);
if (td.elem_length > 0) {
auto loop_data = lb_loop_start(p, cast(isize)td.elem_length, t_i32);
{
lbValue dst = td.gep;
dst = lb_emit_ptr_offset(p, dst, loop_data.idx);
lb_emit_store(p, dst, td.value);
}
lb_loop_end(p, loop_data);
} else {
lb_emit_store(p, td.gep, td.value);
}
}
}
@@ -6120,7 +6124,35 @@ gb_internal lbAddr lb_build_addr_compound_lit(lbProcedure *p, Ast *expr) {
}
case Type_Struct:
lb_build_addr_struct_compound_lit_populate(p, expr, type, v);
if (is_type_soa_struct(type)) {
GB_ASSERT(bt->Struct.soa_kind == StructSoa_Fixed);
if (cl->elems.count == 0) {
break;
}
lb_addr_store(p, v, lb_const_value(p->module, type, exact_value_compound(expr)));
auto temp_data = array_make<lbCompoundLitElemTempData>(temporary_allocator(), 0, cl->elems.count);
lb_build_addr_compound_lit_populate(p, cl->elems, &temp_data, type);
for (auto const &td : temp_data) {
GB_ASSERT(td.value.value != nullptr);
lbValue offset = lb_const_int(p->module, t_i32, td.elem_index);
if (td.elem_length > 0) {
auto loop_data = lb_loop_start(p, cast(isize)td.elem_length, t_i32);
{
lbValue index = lb_emit_arith(p, Token_Add, offset, loop_data.idx, t_i32);
lbAddr dst = lb_addr_soa_variable(v.addr, index, td.expr);
lb_addr_store(p, dst, td.value);
}
lb_loop_end(p, loop_data);
} else {
lbValue index = offset;
lbAddr dst = lb_addr_soa_variable(v.addr, index, td.expr);
lb_addr_store(p, dst, td.value);
}
}
} else {
lb_build_addr_struct_compound_lit_populate(p, expr, type, v);
}
break;
case Type_Map: {

View File

@@ -1024,10 +1024,16 @@ gb_internal lbValue lb_emit_call_internal(lbProcedure *p, lbValue value, lbValue
}
for_array(i, ft->args) {
// lbArg_Ignore args are not present in the call arguments, so they must not
// advance param_offset (mirrors lb_add_function_type_attributes)
if (ft->args[i].kind == lbArg_Ignore) {
continue;
}
LLVMAttributeRef attribute = ft->args[i].attribute;
if (attribute != nullptr) {
LLVMAddCallSiteAttribute(ret, param_offset + cast(LLVMAttributeIndex)i, attribute);
LLVMAddCallSiteAttribute(ret, param_offset, attribute);
}
param_offset += 1;
}
switch (inlining) {
@@ -4785,6 +4791,12 @@ gb_internal lbValue lb_build_builtin_proc(lbProcedure *p, Ast *expr, TypeAndValu
gb_internal lbValue lb_handle_param_value(lbProcedure *p, Type *parameter_type, ParameterValue const &param_value, TypeProc *procedure_type, Ast* call_expression) {
switch (param_value.kind) {
case ParameterValue_Constant:
if (param_value.proc_entity != nullptr && is_type_proc(parameter_type)) {
lbValue v = lb_find_procedure_value_from_entity(p->module, param_value.proc_entity);
if (v.value != nullptr) {
return lb_emit_conv(p, v, parameter_type);
}
}
if (is_type_constant_type(parameter_type)) {
auto res = lb_const_value(p->module, parameter_type, param_value.value);
return res;
@@ -4904,6 +4916,79 @@ gb_internal void lb_add_values_to_array(lbProcedure *p, Array<lbValue> *args, lb
}
}
gb_internal lbValue lb_build_variadic_slice(lbProcedure *p, Type *slice_type, Slice<lbValue> var_args) {
GB_ASSERT(is_type_slice(slice_type));
if (var_args.count == 0) {
return lb_const_nil(p->module, slice_type);
}
Type *elem_type = slice_type->Slice.elem;
lbAddr slice = {};
for (auto const &vr : p->variadic_reuses) {
if (are_types_identical(vr.slice_type, slice_type)) {
slice = vr.slice_addr;
break;
}
}
DeclInfo *d = decl_info_of_entity(p->entity);
if (d != nullptr && slice.addr.value == nullptr) {
for (auto const &vr : d->variadic_reuses) {
if (are_types_identical(vr.slice_type, slice_type)) {
#if LLVM_VERSION_MAJOR >= 13
// NOTE(bill): No point wasting even more memory, just reuse this stack variable too
if (p->variadic_reuses.count > 0) {
slice = p->variadic_reuses[0].slice_addr;
} else {
slice = lb_add_local_generated(p, slice_type, true);
}
// NOTE(bill): Change the underlying type to match the specific type
slice.addr.type = alloc_type_pointer(slice_type);
#else
slice = lb_add_local_generated(p, slice_type, true);
#endif
array_add(&p->variadic_reuses, lbVariadicReuseSlices{slice_type, slice});
break;
}
}
}
lbValue base_array_ptr = p->variadic_reuse_base_array_ptr.addr;
if (base_array_ptr.value == nullptr) {
if (d != nullptr) {
i64 max_bytes = d->variadic_reuse_max_bytes;
i64 max_align = gb_max(d->variadic_reuse_max_align, 16);
p->variadic_reuse_base_array_ptr = lb_add_local_generated(p, alloc_type_array(t_u8, max_bytes), true);
lb_try_update_alignment(p->variadic_reuse_base_array_ptr.addr, cast(unsigned)max_align);
base_array_ptr = p->variadic_reuse_base_array_ptr.addr;
} else {
base_array_ptr = lb_add_local_generated(p, alloc_type_array(elem_type, var_args.count), true).addr;
}
}
if (slice.addr.value == nullptr) {
slice = lb_add_local_generated(p, slice_type, true);
}
GB_ASSERT(base_array_ptr.value != nullptr);
GB_ASSERT(slice.addr.value != nullptr);
base_array_ptr = lb_emit_conv(p, base_array_ptr, alloc_type_pointer(alloc_type_array(elem_type, var_args.count)));
for_array(i, var_args) {
lbValue addr = lb_emit_array_epi(p, base_array_ptr, cast(i32)i);
lbValue var_arg = lb_emit_conv(p, var_args[i], elem_type);
lb_emit_store(p, addr, var_arg);
}
lbValue base_elem = lb_emit_array_epi(p, base_array_ptr, 0);
lbValue len = lb_const_int(p->module, t_int, var_args.count);
lb_fill_slice(p, slice, base_elem, len);
return lb_addr_load(p, slice);
}
gb_internal lbValue lb_build_call_expr_internal(lbProcedure *p, Ast *expr, lbValue *sret_dst) {
lbModule *m = p->module;
@@ -4989,8 +5074,45 @@ gb_internal lbValue lb_build_call_expr_internal(lbProcedure *p, Ast *expr, lbVal
bool vari_expand = (ce->ellipsis.pos.line != 0);
bool is_c_vararg = pt->c_vararg;
bool has_tuple_positional_arg = false;
if (pt->variadic && !is_c_vararg && !vari_expand) {
for (Ast *arg : ce->split_args->positional) {
TypeAndValue tav = type_and_value_of_expr(arg);
if (is_type_tuple(tav.type)) {
has_tuple_positional_arg = true;
break;
}
}
}
for_array(i, ce->split_args->positional) {
if (has_tuple_positional_arg) {
auto flat_args = array_make<lbValue>(heap_allocator());
defer (array_free(&flat_args));
for_array(i, ce->split_args->positional) {
Entity *e = pt->params->Tuple.variables[gb_min(i, cast(isize)pt->variadic_index)];
if (e->kind == Entity_TypeName) {
array_add(&flat_args, lb_const_nil(p->module, e->type));
} else if (e->kind == Entity_Constant) {
array_add(&flat_args, lb_const_value(p->module, e->type, e->Constant.value));
} else {
GB_ASSERT(e->kind == Entity_Variable);
lbValue arg = lb_build_expr(p, ce->split_args->positional[i]);
lb_add_values_to_array(p, &flat_args, arg);
}
}
isize fixed_count = pt->variadic_index;
isize supplied_fixed_count = gb_min(fixed_count, flat_args.count);
for (isize i = 0; i < supplied_fixed_count; i++) {
array_add(&args, flat_args[i]);
}
array_resize(&args, fixed_count);
Type *slice_type = pt->params->Tuple.variables[pt->variadic_index]->type;
auto var_args = slice(slice_from_array(flat_args), supplied_fixed_count, flat_args.count);
array_add(&args, lb_build_variadic_slice(p, slice_type, var_args));
} else for_array(i, ce->split_args->positional) {
Entity *e = pt->params->Tuple.variables[i];
if (e->kind == Entity_TypeName) {
array_add(&args, lb_const_nil(p->module, e->type));
@@ -5032,82 +5154,13 @@ gb_internal lbValue lb_build_call_expr_internal(lbProcedure *p, Ast *expr, lbVal
variadic_args = lb_build_expr(p, variadic[0]);
variadic_args = lb_emit_conv(p, variadic_args, slice_type);
} else {
Type *elem_type = slice_type->Slice.elem;
auto var_args = array_make<lbValue>(heap_allocator(), 0, variadic.count);
defer (array_free(&var_args));
for (Ast *var_arg : variadic) {
lbValue v = lb_build_expr(p, var_arg);
lb_add_values_to_array(p, &var_args, v);
}
isize slice_len = var_args.count;
if (slice_len > 0) {
lbAddr slice = {};
for (auto const &vr : p->variadic_reuses) {
if (are_types_identical(vr.slice_type, slice_type)) {
slice = vr.slice_addr;
break;
}
}
DeclInfo *d = decl_info_of_entity(p->entity);
if (d != nullptr && slice.addr.value == nullptr) {
for (auto const &vr : d->variadic_reuses) {
if (are_types_identical(vr.slice_type, slice_type)) {
#if LLVM_VERSION_MAJOR >= 13
// NOTE(bill): No point wasting even more memory, just reuse this stack variable too
if (p->variadic_reuses.count > 0) {
slice = p->variadic_reuses[0].slice_addr;
} else {
slice = lb_add_local_generated(p, slice_type, true);
}
// NOTE(bill): Change the underlying type to match the specific type
slice.addr.type = alloc_type_pointer(slice_type);
#else
slice = lb_add_local_generated(p, slice_type, true);
#endif
array_add(&p->variadic_reuses, lbVariadicReuseSlices{slice_type, slice});
break;
}
}
}
lbValue base_array_ptr = p->variadic_reuse_base_array_ptr.addr;
if (base_array_ptr.value == nullptr) {
if (d != nullptr) {
i64 max_bytes = d->variadic_reuse_max_bytes;
i64 max_align = gb_max(d->variadic_reuse_max_align, 16);
p->variadic_reuse_base_array_ptr = lb_add_local_generated(p, alloc_type_array(t_u8, max_bytes), true);
lb_try_update_alignment(p->variadic_reuse_base_array_ptr.addr, cast(unsigned)max_align);
base_array_ptr = p->variadic_reuse_base_array_ptr.addr;
} else {
base_array_ptr = lb_add_local_generated(p, alloc_type_array(elem_type, slice_len), true).addr;
}
}
if (slice.addr.value == nullptr) {
slice = lb_add_local_generated(p, slice_type, true);
}
GB_ASSERT(base_array_ptr.value != nullptr);
GB_ASSERT(slice.addr.value != nullptr);
base_array_ptr = lb_emit_conv(p, base_array_ptr, alloc_type_pointer(alloc_type_array(elem_type, slice_len)));
for (isize i = 0; i < var_args.count; i++) {
lbValue addr = lb_emit_array_epi(p, base_array_ptr, cast(i32)i);
lbValue var_arg = var_args[i];
var_arg = lb_emit_conv(p, var_arg, elem_type);
lb_emit_store(p, addr, var_arg);
}
lbValue base_elem = lb_emit_array_epi(p, base_array_ptr, 0);
lbValue len = lb_const_int(p->module, t_int, slice_len);
lb_fill_slice(p, slice, base_elem, len);
variadic_args = lb_addr_load(p, slice);
}
variadic_args = lb_build_variadic_slice(p, slice_type, slice_from_array(var_args));
}
}
array_add(&args, variadic_args);

View File

@@ -6,13 +6,35 @@ gb_internal bool in_vet_packages(AstFile *file) {
if (file == nullptr) {
return true;
}
if (file->pkg == nullptr) {
return true;
}
if (file->pkg_decl == nullptr) {
return true;
}
if (build_context.vet_packages.entries.count == 0) {
return true;
}
return string_set_exists(&build_context.vet_packages, file->pkg->name);
String pkg_name = {};
if (file->pkg->name.len > 0) {
pkg_name = file->pkg->name;
} else if (file->pkg_decl->kind == Ast_PackageDecl) {
Token name_token = file->pkg_decl->PackageDecl.name;
if (name_token.kind == Token_Ident) {
pkg_name = name_token.string;
}
}
if (pkg_name.len == 0) {
return true;
}
return string_set_exists(&build_context.vet_packages, pkg_name);
}
gb_internal u64 ast_file_vet_flags(AstFile *f) {

View File

@@ -1,3 +1,4 @@
#+build !netbsd
package test_core_math_rand
import "core:math"
@@ -10,6 +11,9 @@ Generator :: struct {
biased: bool,
}
// Disable on NetBSD due to Illegal Instruction on CI, even with `microarch:native`
// `@(test, disable="...")` still runs the test.
@(test)
test_prngs :: proc(t: ^testing.T) {
gens := []Generator {

View File

@@ -525,6 +525,36 @@ join_url_test :: proc(t: ^testing.T) {
}
}
@test
percent_encode_test :: proc(t: ^testing.T) {
test_cases := []struct{input, expected: string} {
// Bytes < 0x10 must be zero-padded to two hex digits
{"\n", "%0A"},
{"\t", "%09"},
{"\r", "%0D"},
{"a\nb", "a%0Ab"},
{"\x00", "%00"},
// Bytes >= 0x10
{" ", "%20"},
{"😃", "%F0%9F%98%83"},
// Unreserved characters pass through unescaped
{"AZaz09-_.~", "AZaz09-_.~"},
}
for test in test_cases {
encoded := net.percent_encode(test.input)
defer delete(encoded)
testing.expectf(t, encoded == test.expected, "Expected `net.percent_encode(%q)` to return %q, got %q", test.input, test.expected, encoded)
decoded, ok := net.percent_decode(encoded)
defer delete(decoded)
testing.expectf(t, ok, "Expected `net.percent_decode(%q)` to succeed", encoded)
testing.expectf(t, decoded == test.input, "Expected percent-encoding roundtrip for %q, got %q", test.input, decoded)
}
}
@test
test_udp_echo :: proc(t: ^testing.T) {
endpoint := net.Endpoint{address=net.IP4_Address{127, 0, 0, 1}, port=0}

View File

@@ -0,0 +1,62 @@
#+build !netbsd
package test_core_slice
import "core:slice"
import "core:testing"
import "core:math/rand"
// Disable on NetBSD due to Illegal Instruction on CI, even with `microarch:native`
// `@(test, disable="...")` still runs the test.
@(test)
test_unique :: proc(t: ^testing.T) {
for v in UNIQUE_TEST_VECTORS {
assorted := v[0]
expected := v[1]
uniq := slice.unique(assorted)
testing.expectf(t, slice.equal(uniq, expected), "Expected slice.uniq(%v) == %v, got %v", v[0], v[1], uniq)
}
for v in UNIQUE_TEST_VECTORS {
assorted := v[0]
expected := v[1]
uniq := slice.unique_proc(assorted, proc(a, b: int) -> bool {
return a == b
})
testing.expectf(t, slice.equal(uniq, expected), "Expected slice.unique_proc(%v, ...) == %v, got %v", v[0], v[1], uniq)
}
r := rand.create(t.seed)
context.random_generator = rand.default_random_generator(&r)
// 10_000 random tests
for _ in 0..<10_000 {
assorted: [dynamic]i64
expected: [dynamic]i64
// Prime with 1 value
old := rand.int63()
append(&assorted, old)
append(&expected, old)
// Add 99 additional random values
for _ in 1..<100 {
new := rand.int63()
append(&assorted, new)
if old != new {
append(&expected, new)
}
old = new
}
original := slice.clone(assorted[:])
uniq := slice.unique(assorted[:])
testing.expectf(t, slice.equal(uniq, expected[:]), "Expected slice.uniq(%v) == %v, got %v", original, expected, uniq)
delete(assorted)
delete(original)
delete(expected)
}
}

View File

@@ -225,59 +225,6 @@ UNIQUE_TEST_VECTORS :: [][2][]int{
{{1,2,4,4,5}, {1,2,4,5}},
}
@test
test_unique :: proc(t: ^testing.T) {
for v in UNIQUE_TEST_VECTORS {
assorted := v[0]
expected := v[1]
uniq := slice.unique(assorted)
testing.expectf(t, slice.equal(uniq, expected), "Expected slice.uniq(%v) == %v, got %v", v[0], v[1], uniq)
}
for v in UNIQUE_TEST_VECTORS {
assorted := v[0]
expected := v[1]
uniq := slice.unique_proc(assorted, proc(a, b: int) -> bool {
return a == b
})
testing.expectf(t, slice.equal(uniq, expected), "Expected slice.unique_proc(%v, ...) == %v, got %v", v[0], v[1], uniq)
}
r := rand.create(t.seed)
context.random_generator = rand.default_random_generator(&r)
// 10_000 random tests
for _ in 0..<10_000 {
assorted: [dynamic]i64
expected: [dynamic]i64
// Prime with 1 value
old := rand.int63()
append(&assorted, old)
append(&expected, old)
// Add 99 additional random values
for _ in 1..<100 {
new := rand.int63()
append(&assorted, new)
if old != new {
append(&expected, new)
}
old = new
}
original := slice.clone(assorted[:])
uniq := slice.unique(assorted[:])
testing.expectf(t, slice.equal(uniq, expected[:]), "Expected slice.uniq(%v) == %v, got %v", original, expected, uniq)
delete(assorted)
delete(original)
delete(expected)
}
}
@test
test_compare_empty :: proc(t: ^testing.T) {
a := []int{}

View File

@@ -9,6 +9,11 @@ Test_Case :: struct {
expected_clusters: int,
}
Text_Test_Case :: struct {
str: string,
expected_output: []string,
}
run_test_cases :: proc(t: ^testing.T, test_cases: []Test_Case, loc := #caller_location) {
failed := 0
for c, i in test_cases {
@@ -132,3 +137,32 @@ test_width :: proc(t: ^testing.T) {
testing.expect_value(t, width, 50)
}
}
@test
test_grapheme_cluster_text :: proc(t: ^testing.T) {
cases :: []Text_Test_Case {
{"abc", {"a", "b", "c"}},
{"é", {"é"}},
{"中", {"中"}},
{"\U0001F1FA\U0001F1F8", {"\U0001F1FA\U0001F1F8"}},
{"\U0001F1FA\U0001F1F8\U0001F1EE\U0001F1EA", {"\U0001F1FA\U0001F1F8", "\U0001F1EE\U0001F1EA"}},
{"\U0001F468\U0001F469\U0001F467\U0001F466", {"\U0001F468\U0001F469\U0001F467\U0001F466"}},
{"\U0001F44D\U0001F3FD", {"\U0001F44D\U0001F3FD"}},
{"a\r\nb", {"a", "\r\n", "b"}},
}
for c in cases {
it := utf8.decode_grapheme_iterator_make(c.str)
i := 0
for text, grapheme in utf8.decode_grapheme_iterate(&it) {
if !testing.expectf(t, i < len(c.expected_output), "%q: expected %d clusters, got at least %d", c.str, len(c.expected_output), i + 1) {
break
}
testing.expectf(t, text == c.expected_output[i], "%q cluster %d: expected text %q, got %q", c.str, i, c.expected_output[i], text)
testing.expectf(t, text == c.str[grapheme.byte_index:][:len(text)], "%q cluster %d: text does not start at byte_index %d", c.str, i, grapheme.byte_index)
i += 1
}
testing.expectf(t, i == len(c.expected_output), "%q: expected %d clusters, got %d", c.str, len(c.expected_output), i)
}
}

View File

@@ -0,0 +1,25 @@
package test_internal
import "core:testing"
@(test)
array_count_from_integral_float :: proc(t: ^testing.T) {
testing.expect_value(t, len([3.0]u8{}), 3)
testing.expect_value(t, len([0.0]u8{}), 0)
testing.expect_value(t, size_of([3.0]u32), 12)
// folded constant expressions
Halved :: 6.0 / 2.0
Summed :: 1.5 + 1.5
testing.expect_value(t, len([Halved]u8{}), 3)
testing.expect_value(t, len([Summed]u8{}), 3)
// NOTE: keep below one BigInt limb: 2^28 on windows, 2^60 on linux
testing.expect_value(t, len([65536.0]struct{}{}), 1 << 16)
testing.expect_value(t, size_of(matrix[2.0, 3.0]f32), 24)
testing.expect_value(t, size_of(#simd[4.0]u8), 4)
Sparse :: [2.0]u8
testing.expect_value(t, len(Sparse{1, 2}), 2)
}

View File

@@ -26,6 +26,7 @@ set COMMON=-define:ODIN_TEST_FANCY=false -file -vet -strict-style -ignore-unused
..\..\..\odin build ..\test_issue_5097.odin %COMMON% || exit /b
..\..\..\odin build ..\test_issue_5097-2.odin %COMMON% || exit /b
..\..\..\odin build ..\test_issue_5265.odin %COMMON% || exit /b
..\..\..\odin build ..\test_issue_5573.odin %COMMON% 2>&1 | find /c "Error:" | findstr /x "2" || exit /b
..\..\..\odin test ..\test_issue_5699.odin %COMMON% || exit /b
..\..\..\odin test ..\test_issue_6068.odin %COMMON% || exit /b
..\..\..\odin test ..\test_issue_6101.odin %COMMON% || exit /b
@@ -37,9 +38,11 @@ set COMMON=-define:ODIN_TEST_FANCY=false -file -vet -strict-style -ignore-unused
..\..\..\odin test ..\test_pr_6470.odin -define:TEST_EXPECT_FAILURE=true %COMMON% 2>&1 | find /c "Error:" | findstr /x "1" || exit /b
..\..\..\odin test ..\test_pr_6476.odin %COMMON% || exit /b
..\..\..\odin check ..\test_issue_6484.odin -no-entry-point %COMMON% || exit /b
..\..\..\odin test ..\test_issue_6753.odin %COMMON% || exit /b
..\..\..\odin check ..\test_issue_6874.odin %COMMON% 2>&1 | find /c "Error:" | findstr /x "1" || exit /b
..\..\..\odin check ..\test_issue_6979.odin -no-entry-point %COMMON% || exit /b
..\..\..\odin build ..\test_issue_7037.odin %COMMON% -o:none || exit /b
..\..\..\odin build ..\test_issue_7188.odin %COMMON% || exit /b
..\..\..\odin build ..\test_issue_7073-1.odin %COMMON% 2>&1 | find /c "Error:" | findstr /x "2" || exit /b
@echo off

View File

@@ -7,10 +7,9 @@ ODIN=../../../odin
COMMON="-define:ODIN_TEST_FANCY=false -file -vet -strict-style -ignore-unused-defineables -microarch:native"
COMMON_CHECK="-define:ODIN_TEST_FANCY=false -file -vet -strict-style -ignore-unused-defineables"
set -x
$ODIN test ../test_issue_829.odin $COMMON
$ODIN test ../test_issue_829.odin $COMMON
$ODIN test ../test_issue_1592.odin $COMMON
$ODIN test ../test_issue_1730.odin $COMMON
$ODIN test ../test_issue_2056.odin $COMMON
@@ -24,7 +23,7 @@ $ODIN test ../test_issue_3435.odin $COMMON
$ODIN test ../test_issue_4210.odin $COMMON
$ODIN test ../test_issue_4364.odin $COMMON
$ODIN test ../test_issue_4584.odin $COMMON
if [[ $($ODIN build ../test_issue_2395.odin $COMMON 2>&1 >/dev/null | grep -c "Error:") -eq 2 ]] ; then
if [[ $($ODIN build ../test_issue_2395.odin $COMMON 2>&1 >/dev/null | grep -c "Error:") -eq 2 ]]; then
echo "SUCCESSFUL 1/1"
else
echo "SUCCESSFUL 0/1"
@@ -34,6 +33,12 @@ $ODIN build ../test_issue_5043.odin $COMMON
$ODIN build ../test_issue_5097.odin $COMMON
$ODIN build ../test_issue_5097-2.odin $COMMON
$ODIN build ../test_issue_5265.odin $COMMON
if [[ $($ODIN build ../test_issue_5573.odin $COMMON 2>&1 >/dev/null | grep -c "Error:") -eq 2 ]]; then
echo "SUCCESSFUL 1/1"
else
echo "SUCCESSFUL 0/1"
exit 1
fi
$ODIN test ../test_issue_5699.odin $COMMON
$ODIN test ../test_issue_6068.odin $COMMON
$ODIN test ../test_issue_6101.odin $COMMON
@@ -43,25 +48,25 @@ $ODIN test ../test_issue_6344.odin $COMMON -o:speed
$ODIN test ../test_issue_6396.odin $COMMON
$ODIN test ../test_pr_6476.odin $COMMON
if [[ $($ODIN build ../test_issue_6240.odin $COMMON 2>&1 >/dev/null | grep -c "Error:") -eq 3 ]] ; then
if [[ $($ODIN build ../test_issue_6240.odin $COMMON 2>&1 >/dev/null | grep -c "Error:") -eq 3 ]]; then
echo "SUCCESSFUL 1/1"
else
echo "SUCCESSFUL 0/1"
exit 1
fi
if [[ $($ODIN build ../test_issue_6401.odin $COMMON 2>&1 >/dev/null | grep -c "Error:") -eq 3 ]] ; then
if [[ $($ODIN build ../test_issue_6401.odin $COMMON 2>&1 >/dev/null | grep -c "Error:") -eq 3 ]]; then
echo "SUCCESSFUL 1/1"
else
echo "SUCCESSFUL 0/1"
exit 1
fi
if [[ $($ODIN build ../test_issue_6594.odin $COMMON 2>&1 >/dev/null | grep -c "Error:") -eq 1 ]] ; then
if [[ $($ODIN build ../test_issue_6594.odin $COMMON 2>&1 >/dev/null | grep -c "Error:") -eq 1 ]]; then
echo "SUCCESSFUL 1/1"
else
echo "SUCCESSFUL 0/1"
exit 1
fi
if [[ $($ODIN build ../test_issue_6621.odin $COMMON 2>&1 >/dev/null | grep -c "Error:") -eq 1 ]] ; then
if [[ $($ODIN build ../test_issue_6621.odin $COMMON 2>&1 >/dev/null | grep -c "Error:") -eq 1 ]]; then
echo "SUCCESSFUL 1/1"
else
echo "SUCCESSFUL 0/1"
@@ -69,14 +74,15 @@ else
fi
$ODIN test ../test_issue_6419.odin $COMMON
$ODIN test ../test_pr_6470.odin $COMMON
if [[ $($ODIN test ../test_pr_6470.odin -define:TEST_EXPECT_FAILURE=true $COMMON 2>&1 >/dev/null | grep -c "Error:") -eq 1 ]] ; then
if [[ $($ODIN test ../test_pr_6470.odin -define:TEST_EXPECT_FAILURE=true $COMMON 2>&1 >/dev/null | grep -c "Error:") -eq 1 ]]; then
echo "SUCCESSFUL 1/1"
else
echo "SUCCESSFUL 0/1"
exit 1
fi
$ODIN check ../test_issue_6484.odin -no-entry-point $COMMON_CHECK
if [[ $($ODIN check ../test_issue_6874.odin $COMMON_CHECK 2>&1 >/dev/null | grep -c "Error:") -eq 1 ]] ; then
$ODIN test ../test_issue_6753.odin $COMMON
if [[ $($ODIN check ../test_issue_6874.odin $COMMON_CHECK 2>&1 >/dev/null | grep -c "Error:") -eq 1 ]]; then
echo "SUCCESSFUL 1/1"
else
echo "SUCCESSFUL 0/1"
@@ -84,15 +90,17 @@ else
fi
$ODIN check ../test_issue_6979.odin -no-entry-point $COMMON_CHECK
$ODIN build ../test_issue_7037.odin $COMMON -o:none
$ODIN build ../test_issue_7167.odin $COMMON
$ODIN build ../test_issue_7188.odin $COMMON
if [[ $($ODIN build ../test_issue_7108.odin $COMMON 2>&1 >/dev/null | grep -c "Error:") -eq 2 ]] ; then
if [[ $($ODIN build ../test_issue_7108.odin $COMMON 2>&1 >/dev/null | grep -c "Error:") -eq 2 ]]; then
echo "SUCCESSFUL 1/1"
else
echo "SUCCESSFUL 0/1"
exit 1
fi
if [[ $($ODIN build ../test_issue_7073-1.odin $COMMON 2>&1 >/dev/null | grep -c "Error:") -eq 2 ]] ; then
if [[ $($ODIN build ../test_issue_7073-1.odin $COMMON 2>&1 >/dev/null | grep -c "Error:") -eq 2 ]]; then
echo "SUCCESSFUL 1/1"
else
echo "SUCCESSFUL 0/1"

View File

@@ -0,0 +1,18 @@
// Tests issue #5573 https://github.com/odin-lang/Odin/issues/5573
package test_issues
poly :: proc(x: $T) -> string {
return "poly"
}
takes_concrete :: proc(f: proc(a: int, b: f32, c: rawptr) -> ^int) {
}
main :: proc() {
// should error - wrong arity, wrong parameter types, wrong return type
mismatched: proc(a: int, b: f32, c: rawptr) -> ^int = poly
_ = mismatched
// should error - same, as a procedure argument
takes_concrete(poly)
}

View File

@@ -0,0 +1,64 @@
// test issue for #6753 https://github.com/odin-lang/odin/issues/6753
package test_issues
import "core:testing"
import "core:fmt"
foo_concrete :: proc(x: int, g: proc(int) -> int) -> int {
return g(x)
}
foo_impossible :: proc(x: int, g: proc(int, int) -> string) -> string {
return "impossible"
}
foo_group :: proc {
foo_concrete,
foo_impossible,
}
f_poly :: proc(x: $T) -> T { return x }
foo_poly :: proc(x: $T, g: proc(T) -> T = f_poly) -> T {
return g(x)
}
@test
test_issue_6753_ambiguous_poly_argument :: proc (t: ^testing.T) {
testing.expect_value(t, foo_group(1, f_poly), 1) // should be no ambiguity whether foo_concrete or foo_impossible
}
@test
test_issue_6753_default_poly_proc :: proc (t: ^testing.T) {
testing.expect_value(t, foo_poly(1), 1)
}
@test
test_issue_6753_parapoly_proc_variable :: proc(t: ^testing.T) {
p: proc(int) -> int = f_poly
testing.expect(t, p != nil, "polymorphic procedure was not instantiated")
testing.expect_value(t, p(123), 123)
}
// -- Fixing above led to some new bugs surfacing --
@test
test_issue_6753_parapoly_proc_as_argument :: proc(t: ^testing.T) {
testing.expect(t, foo_concrete(123, f_poly) == 123, "failed to pass poly proc as argument")
}
@test
test_issue_6753_parapoly_with_default_proc_same_generic_type_T :: proc(t: ^testing.T) {
testing.expect_value(t, foo_poly(123), 123)
testing.expect_value(t, foo_poly(123, f_poly), 123)
}
// all together now
describe :: proc(x: $T) -> string { return fmt.tprintf("#%v", x) }
describe_bytes :: proc(x: []byte) -> string { return "bytes" }
bar_poly :: proc(x: $T, g: proc(x: T) -> string = describe) -> string { return g(x) }
bar_bytes :: proc(x: []byte, g: proc(x: []byte) -> string) -> string { return g(x) }
bar_group :: proc { bar_poly, bar_bytes }
@test
test_issue_6753_parapoly_default_in_group :: proc(t: ^testing.T) {
testing.expect_value(t, bar_group(123, describe), "#123")
testing.expect_value(t, bar_group("hi"), "#hi")
testing.expect_value(t, bar_group([]byte{1, 2}, describe_bytes), "bytes")
}

View File

@@ -0,0 +1,9 @@
// Tests issue #7167 https://github.com/odin-lang/Odin/issues/7167
package test_issues
import "core:fmt"
import "core:path/filepath"
main :: proc() {
fmt.printf(filepath.join({}))
}

View File

@@ -0,0 +1,13 @@
package test_issues
main :: proc() {
val: f32 = 42.0
// unable to broadcast like ([4][4]f32)(1) or (#soa[4][4]f32)(([4]f32)(1))
_ = #soa[2][2]f32 {
0..<2 = val,
}
vtxs := #soa[33][2]f32 {
0..<33 = val,
}
_ = vtxs.x[32]
}

View File

@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:d698fbbe655db1d1ec6f52dcc23bfed4a2c981fa88040ba449f9f83609edba88
size 3137140
oid sha256:ad5491b77cda430ee03adb68bd6b4d56d3f7d8941327643eecc2b636496acda0
size 1601114

View File

@@ -70,12 +70,19 @@ Darwin)
;;
Linux)
LIB_DIR="../lib/linux-$ARCH"
mkdir -p "$LIB_DIR"
$cc -c -O2 -std=c17 -fPIC -Iinclude src/*.c
$ar rcs "$LIB_DIR/$LIB_NAME" ./*.o
rm ./*.o
mkdir -p "$LIB_DIR" build
for src in src/*.c; do
obj="build/$(basename "${src%.c}.o")"
$cc -c -O2 -std=c17 -fPIC -Iinclude "$src" -o "$obj"
done
# Clean up old library in case `ar` is tempted to preserve old symbols
rm -f "$LIB_DIR/$LIB_NAME"
$ar rcs "$LIB_DIR/$LIB_NAME" build/*.o
$ranlib "$LIB_DIR/$LIB_NAME"
rm -rf build
;;
*)
echo "Error: Unsupported operating system: $(uname -s)"
exit 1
;;