Merge branch 'master' into windows-llvm-13.0.0

This commit is contained in:
gingerBill
2021-10-29 15:18:49 +01:00
19 changed files with 1146 additions and 117 deletions

View File

@@ -32,6 +32,9 @@ add :: proc {
int_add_digit :: proc(dest, a: ^Int, digit: DIGIT, allocator := context.allocator) -> (err: Error)
*/
int_add_digit,
rat_add_rat,
rat_add_int,
int_add_rat,
}
/*
@@ -46,6 +49,9 @@ sub :: proc {
int_sub_digit :: proc(dest, a: ^Int, digit: DIGIT) -> (err: Error)
*/
int_sub_digit,
rat_sub_rat,
rat_sub_int,
int_sub_rat,
}
/*
@@ -67,6 +73,10 @@ is_zero :: proc {
int_is_zero :: proc(a: ^Int) -> bool
*/
int_is_zero,
/*
rat_is_zero :: proc(a: ^Rat) -> bool
*/
rat_is_zero,
}
is_positive :: proc {
@@ -74,6 +84,7 @@ is_positive :: proc {
int_is_positive :: proc(a: ^Int) -> bool
*/
int_is_positive,
rat_is_positive,
}
is_pos :: is_positive
@@ -82,6 +93,7 @@ is_negative :: proc {
int_is_negative :: proc(a: ^Int) -> bool
*/
int_is_negative,
rat_is_negative,
}
is_neg :: is_negative
@@ -90,6 +102,7 @@ is_even :: proc {
int_is_even :: proc(a: ^Int) -> bool
*/
int_is_even,
rat_is_even,
}
is_odd :: proc {
@@ -97,6 +110,7 @@ is_odd :: proc {
int_is_odd :: proc(a: ^Int) -> bool
*/
int_is_odd,
rat_is_odd,
}
is_power_of_two :: proc {

View File

@@ -44,7 +44,20 @@ int_set_from_integer :: proc(dest: ^Int, src: $T, minimize := false, allocator :
return #force_inline internal_int_set_from_integer(dest, src, minimize)
}
set :: proc { int_set_from_integer, int_copy, int_atoi, }
set :: proc {
int_set_from_integer,
int_copy,
int_atoi,
rat_set_f64,
rat_set_f32,
rat_set_f16,
rat_set_u64,
rat_set_i64,
rat_set_int,
rat_set_digit,
rat_set_rat,
}
/*
Copy one `Int` to another.
@@ -66,7 +79,10 @@ int_copy :: proc(dest, src: ^Int, minimize := false, allocator := context.alloca
return #force_inline internal_int_copy(dest, src, minimize)
}
copy :: proc { int_copy, }
copy :: proc {
int_copy,
rat_copy,
}
/*
In normal code, you can also write `a, b = b, a`.
@@ -77,7 +93,7 @@ int_swap :: proc(a, b: ^Int) {
assert_if_nil(a, b)
#force_inline internal_swap(a, b)
}
swap :: proc { int_swap, }
swap :: proc { int_swap, rat_swap }
/*
Set `dest` to |`src`|.
@@ -98,7 +114,7 @@ int_abs :: proc(dest, src: ^Int, allocator := context.allocator) -> (err: Error)
platform_abs :: proc(n: $T) -> T where intrinsics.type_is_integer(T) {
return n if n >= 0 else -n
}
abs :: proc{ int_abs, platform_abs, }
abs :: proc{ int_abs, platform_abs, rat_abs }
/*
Set `dest` to `-src`.
@@ -115,7 +131,7 @@ int_neg :: proc(dest, src: ^Int, allocator := context.allocator) -> (err: Error)
return #force_inline internal_int_neg(dest, src)
}
neg :: proc { int_neg, }
neg :: proc { int_neg, rat_neg }
/*
Helpers to extract values from the `Int`.
@@ -788,7 +804,10 @@ destroy_constants :: proc() {
}
assert_if_nil :: proc{assert_if_nil_int}
assert_if_nil :: proc{
assert_if_nil_int,
assert_if_nil_rat,
}
assert_if_nil_int :: #force_inline proc(integers: ..^Int, loc := #caller_location) {
for i in integers {
@@ -796,3 +815,8 @@ assert_if_nil_int :: #force_inline proc(integers: ..^Int, loc := #caller_locatio
}
}
assert_if_nil_rat :: #force_inline proc(rationals: ..^Rat, loc := #caller_location) {
for r in rationals {
assert(r != nil, "(nil)", loc)
}
}

View File

@@ -1042,7 +1042,10 @@ internal_is_initialized :: proc { internal_int_is_initialized, }
internal_int_is_zero :: #force_inline proc(a: ^Int) -> (zero: bool) {
return a.used == 0
}
internal_is_zero :: proc { internal_int_is_zero }
internal_is_zero :: proc {
internal_rat_is_zero,
internal_int_is_zero,
}
/*
This procedure will return `true` if the `Int` is positive, `false` if not.
@@ -1865,7 +1868,10 @@ internal_int_destroy :: proc(integers: ..^Int) {
a = &Int{}
}
}
internal_destroy :: proc{ internal_int_destroy, }
internal_destroy :: proc{
internal_int_destroy,
internal_rat_destroy,
}
/*
Helpers to set an `Int` to a specific value.
@@ -1950,13 +1956,14 @@ internal_copy :: proc { internal_int_copy, }
This helper swaps completely.
*/
internal_int_swap :: #force_inline proc(a, b: ^Int) {
a := a; b := b
a.used, b.used = b.used, a.used
a.sign, b.sign = b.sign, a.sign
a.digit, b.digit = b.digit, a.digit
}
internal_swap :: proc { internal_int_swap, }
internal_swap :: proc {
internal_int_swap,
internal_rat_swap,
}
/*
Set `dest` to |`src`|.

View File

@@ -152,9 +152,18 @@ int_mul :: proc(dest, src, multiplier: ^Int, allocator := context.allocator) ->
return #force_inline internal_int_mul(dest, src, multiplier)
}
mul :: proc { int_mul, int_mul_digit, }
mul :: proc {
int_mul,
int_mul_digit,
rat_mul_rat,
rat_mul_int,
int_mul_rat,
}
int_sqr :: proc(dest, src: ^Int) -> (err: Error) { return mul(dest, src, src) }
rat_sqr :: proc(dest, src: ^Rat) -> (err: Error) { return mul(dest, src, src) }
sqr :: proc { int_sqr, rat_sqr }
sqr :: proc(dest, src: ^Int) -> (err: Error) { return mul(dest, src, src) }
/*
divmod.
@@ -200,7 +209,13 @@ int_div_digit :: proc(quotient, numerator: ^Int, denominator: DIGIT, allocator :
_ = #force_inline internal_divmod(quotient, numerator, denominator) or_return
return
}
div :: proc { int_div, int_div_digit, }
div :: proc {
int_div,
int_div_digit,
rat_div_rat,
rat_div_int,
int_div_rat,
}
/*
remainder = numerator % denominator.

540
core/math/big/rat.odin Normal file
View File

@@ -0,0 +1,540 @@
package math_big
import "core:builtin"
import "core:intrinsics"
import "core:math"
Rat :: struct {
a, b: Int,
}
rat_set_f64 :: proc(dst: ^Rat, f: f64, allocator := context.allocator) -> (err: Error) {
assert_if_nil(dst)
context.allocator = allocator
EXP_MASK :: 1<<11 - 1
bits := transmute(u64)f
mantissa := bits & (1<<52 - 1)
exp := int((bits>>52) & EXP_MASK)
int_set_from_integer(&dst.b, 1) or_return
switch exp {
case EXP_MASK:
dst.a.flags += {.Inf}
return
case 0:
exp -= 1022
case:
mantissa |= 1<<52
exp -= 1023
}
shift := 52 - exp
for mantissa&1 == 0 && shift > 0 {
mantissa >>= 1
shift -= 1
}
int_set_from_integer(&dst.a, mantissa) or_return
dst.a.sign = .Negative if f < 0 else .Zero_or_Positive
if shift > 0 {
internal_int_shl_digit(&dst.b, shift) or_return
} else {
internal_int_shl_digit(&dst.a, -shift) or_return
}
return internal_rat_norm(dst)
}
rat_set_f32 :: proc(dst: ^Rat, f: f32, allocator := context.allocator) -> (err: Error) {
return rat_set_f64(dst, f64(f), allocator)
}
rat_set_f16 :: proc(dst: ^Rat, f: f16, allocator := context.allocator) -> (err: Error) {
return rat_set_f64(dst, f64(f), allocator)
}
rat_set_frac :: proc{rat_set_frac_digit, rat_set_frac_int}
rat_set_frac_digit :: proc(dst: ^Rat, a, b: DIGIT, allocator := context.allocator) -> (err: Error) {
assert_if_nil(dst)
if b == 0 {
return .Division_by_Zero
}
context.allocator = allocator
internal_set(&dst.a, a) or_return
internal_set(&dst.b, b) or_return
return internal_rat_norm(dst)
}
rat_set_frac_int :: proc(dst: ^Rat, a, b: ^Int, allocator := context.allocator) -> (err: Error) {
assert_if_nil(dst)
assert_if_nil(a, b)
if internal_is_zero(b) {
return .Division_by_Zero
}
context.allocator = allocator
internal_set(&dst.a, a) or_return
internal_set(&dst.b, b) or_return
return internal_rat_norm(dst)
}
rat_set_int :: proc(dst: ^Rat, a: ^Int, allocator := context.allocator) -> (err: Error) {
assert_if_nil(dst)
assert_if_nil(a)
context.allocator = allocator
internal_set(&dst.a, a) or_return
internal_set(&dst.b, 1) or_return
return
}
rat_set_digit :: proc(dst: ^Rat, a: DIGIT, allocator := context.allocator) -> (err: Error) {
assert_if_nil(dst)
context.allocator = allocator
internal_set(&dst.a, a) or_return
internal_set(&dst.b, 1) or_return
return
}
rat_set_rat :: proc(dst, x: ^Rat, allocator := context.allocator) -> (err: Error) {
assert_if_nil(dst, x)
context.allocator = allocator
internal_set(&dst.a, &x.a) or_return
internal_set(&dst.b, &x.b) or_return
return
}
rat_set_u64 :: proc(dst: ^Rat, x: u64, allocator := context.allocator) -> (err: Error) {
assert_if_nil(dst)
context.allocator = allocator
internal_set(&dst.a, x) or_return
internal_set(&dst.a, 1) or_return
return
}
rat_set_i64 :: proc(dst: ^Rat, x: i64, allocator := context.allocator) -> (err: Error) {
assert_if_nil(dst)
context.allocator = allocator
internal_set(&dst.a, x) or_return
internal_set(&dst.a, 1) or_return
return
}
rat_copy :: proc(dst, src: ^Rat, minimize := false, allocator := context.allocator) -> (err: Error) {
if (dst == src) { return nil }
assert_if_nil(dst, src)
context.allocator = allocator
int_copy(&dst.a, &src.a, minimize, allocator) or_return
int_copy(&dst.b, &src.b, minimize, allocator) or_return
internal_rat_norm(dst) or_return
return nil
}
internal_rat_destroy :: proc(rationals: ..^Rat) {
rationals := rationals
for z in &rationals {
internal_int_destroy(&z.a, &z.b)
}
}
internal_rat_norm :: proc(z: ^Rat, allocator := context.allocator) -> (err: Error) {
assert_if_nil(z)
context.allocator = allocator
switch {
case internal_is_zero(&z.a):
z.a.sign = .Zero_or_Positive
fallthrough
case internal_is_zero(&z.b):
int_set_from_integer(&z.b, 1) or_return
case:
sign := z.a.sign
z.a.sign = .Zero_or_Positive
z.b.sign = .Zero_or_Positive
f := &Int{}
internal_int_gcd(f, &z.a, &z.b) or_return
if !internal_int_equals_digit(f, 1) {
f.sign = .Zero_or_Positive
internal_int_div(&z.a, &z.a, f) or_return
internal_int_div(&z.b, &z.b, f) or_return
}
z.a.sign = sign
}
return
}
rat_swap :: proc(a, b: ^Rat) {
assert_if_nil(a, b)
#force_inline internal_swap(a, b)
}
internal_rat_swap :: #force_inline proc(a, b: ^Rat) {
internal_int_swap(&a.a, &b.a)
internal_int_swap(&a.b, &b.b)
}
rat_sign :: proc(z: ^Rat) -> Sign {
if z == nil {
return .Zero_or_Positive
}
return z.a.sign
}
rat_is_int :: proc(z: ^Rat) -> bool {
assert_if_nil(z)
return internal_is_zero(&z.a) || internal_int_equals_digit(&z.b, 1)
}
rat_is_zero :: proc(z: ^Rat) -> bool {
return internal_rat_is_zero(z)
}
internal_rat_is_zero :: #force_inline proc(z: ^Rat) -> bool {
assert_if_nil(z)
return internal_is_zero(&z.a)
}
internal_int_mul_denom :: proc(dst, x, y: ^Int, allocator := context.allocator) -> (err: Error) {
assert_if_nil(dst, x, y)
context.allocator = allocator
switch {
case internal_is_zero(x) && internal_is_zero(y):
return internal_set(dst, 1)
case internal_is_zero(x):
return internal_set(dst, y)
case internal_is_zero(y):
return internal_set(dst, x)
}
return int_mul(dst, x, y)
}
internal_int_scale_denom :: proc(dst, x, y: ^Int, allocator := context.allocator) -> (err: Error) {
assert_if_nil(dst, x, y)
if internal_is_zero(y) {
return internal_set(dst, x)
}
int_mul(dst, x, y) or_return
dst.sign = x.sign
return
}
rat_add_rat :: proc(dst, x, y: ^Rat, allocator := context.allocator) -> (err: Error) {
assert_if_nil(dst, x, y)
context.allocator = allocator
a1, a2: Int
defer internal_destroy(&a1, &a2)
internal_int_scale_denom(&a1, &x.a, &y.b) or_return
internal_int_scale_denom(&a2, &y.a, &x.b) or_return
int_add(&dst.a, &a1, &a2) or_return
internal_int_mul_denom(&dst.b, &x.b, &y.b) or_return
return internal_rat_norm(dst)
}
rat_sub_rat :: proc(dst, x, y: ^Rat, allocator := context.allocator) -> (err: Error) {
assert_if_nil(dst, x, y)
context.allocator = allocator
a1, a2 := &Int{}, &Int{}
defer internal_destroy(a1, a2)
internal_int_scale_denom(a1, &x.a, &y.b) or_return
internal_int_scale_denom(a2, &y.a, &x.b) or_return
int_sub(&dst.a, a1, a2) or_return
internal_int_mul_denom(&dst.b, &x.b, &y.b) or_return
return internal_rat_norm(dst)
}
rat_mul_rat :: proc(dst, x, y: ^Rat, allocator := context.allocator) -> (err: Error) {
assert_if_nil(dst, x, y)
context.allocator = allocator
if x == y {
internal_sqr(&dst.a, &x.a) or_return
if internal_is_zero(&x.b) {
internal_set(&dst.b, 1) or_return
} else {
internal_sqr(&dst.a, &x.b) or_return
}
return
}
int_sub(&dst.a, &x.a, &y.a) or_return
internal_int_mul_denom(&dst.b, &x.b, &y.b) or_return
return internal_rat_norm(dst)
}
rat_div_rat :: proc(dst, x, y: ^Rat, allocator := context.allocator) -> (err: Error) {
if internal_rat_is_zero(y) {
return .Division_by_Zero
}
context.allocator = allocator
a, b := &Int{}, &Int{}
defer internal_destroy(a, b)
internal_int_scale_denom(a, &x.a, &y.b) or_return
internal_int_scale_denom(b, &y.a, &x.b) or_return
internal_set(&dst.a, a) or_return
internal_set(&dst.b, b) or_return
internal_int_abs(&dst.a, &dst.a)
internal_int_abs(&dst.b, &dst.b)
dst.a.sign = .Negative if a.sign != b.sign else .Zero_or_Positive
return internal_rat_norm(dst)
}
rat_abs :: proc(dst, x: ^Rat, allocator := context.allocator) -> (err: Error) {
rat_set_rat(dst, x, allocator) or_return
internal_abs(&dst.a, &dst.a, allocator) or_return
return
}
rat_neg :: proc(dst, x: ^Rat, allocator := context.allocator) -> (err: Error) {
rat_set_rat(dst, x, allocator) or_return
internal_neg(&dst.a, &dst.a, allocator) or_return
return
}
rat_is_positive :: proc(z: ^Rat, allocator := context.allocator) -> (ok: bool, err: Error) {
assert_if_nil(z)
a := int_is_positive(&z.a, allocator) or_return
b := int_is_positive(&z.b, allocator) or_return
return !(a ~ b), nil
}
rat_is_negative :: proc(z: ^Rat, allocator := context.allocator) -> (ok: bool, err: Error) {
assert_if_nil(z)
a := int_is_positive(&z.a, allocator) or_return
b := int_is_positive(&z.b, allocator) or_return
return (a ~ b), nil
}
rat_is_even :: proc(z: ^Rat, allocator := context.allocator) -> (ok: bool, err: Error) {
assert_if_nil(z)
if rat_is_int(z) {
return int_is_even(&z.a, allocator)
}
return false, nil
}
rat_is_odd :: proc(z: ^Rat, allocator := context.allocator) -> (ok: bool, err: Error) {
assert_if_nil(z)
if rat_is_int(z) {
return int_is_odd(&z.a, allocator)
}
return false, nil
}
rat_to_f16 :: proc(z: ^Rat, allocator := context.allocator) -> (f: f16, exact: bool, err: Error) {
assert_if_nil(z)
return internal_rat_to_float(f16, z, allocator)
}
rat_to_f32 :: proc(z: ^Rat, allocator := context.allocator) -> (f: f32, exact: bool, err: Error) {
assert_if_nil(z)
return internal_rat_to_float(f32, z, allocator)
}
rat_to_f64 :: proc(z: ^Rat, allocator := context.allocator) -> (f: f64, exact: bool, err: Error) {
assert_if_nil(z)
return internal_rat_to_float(f64, z, allocator)
}
internal_rat_to_float :: proc($T: typeid, z: ^Rat, allocator := context.allocator) -> (f: T, exact: bool, err: Error) where intrinsics.type_is_float(T) {
FSIZE :: 8*size_of(T)
when FSIZE == 16 {
MSIZE :: 10
} else when FSIZE == 32 {
MSIZE :: 23
} else when FSIZE == 64 {
MSIZE :: 52
} else {
#panic("unsupported float type")
}
MSIZE1 :: MSIZE+1
MSIZE2 :: MSIZE+2
ESIZE :: FSIZE - MSIZE1
EBIAS :: 1<<(ESIZE-1) - 1
EMIN :: 1 - EBIAS
EMAX :: EBIAS
assert_if_nil(z)
a, b := &z.a, &z.b
context.allocator = allocator
alen := internal_count_bits(a)
if alen == 0 {
return 0, true, nil
}
blen := internal_count_bits(b)
if blen == 0 {
return T(math.nan_f64()), false, .Division_by_Zero
}
has_sign := a.sign != b.sign
defer if has_sign {
f = -builtin.abs(f)
}
exp := alen - blen
a2, b2 := &Int{}, &Int{}
defer internal_destroy(a2, b2)
internal_int_abs(a2, a) or_return
internal_int_abs(b2, b) or_return
if shift := MSIZE2 - exp; shift > 0 {
internal_int_shl_digit(a2, shift) or_return
} else {
internal_int_shl_digit(b2, -shift) or_return
}
q, r := &Int{}, &Int{}
defer internal_destroy(q, r)
internal_int_divmod(q, r, a2, b2) or_return
has_rem := !internal_is_zero(r)
mantissa := internal_int_get_u64(q) or_return
if mantissa>>MSIZE2 == 1 {
if mantissa&1 == 1 {
has_rem = true
}
mantissa >>= 1
exp += 1
}
assert(mantissa>>MSIZE1 == 1, "invalid bit result")
if EMIN-MSIZE <= exp && exp <= EMIN {
shift := uint(EMIN - (exp - 1))
lost_bits := mantissa & (1<<shift - 1)
has_rem ||= lost_bits != 0
mantissa >>= shift
exp = 2 - EBIAS // exp + shift
}
exact = !has_rem
if mantissa&1 != 0 {
exact = false
if has_rem || mantissa&2 != 0 {
mantissa += 1
if mantissa >= 1<<MSIZE2 {
mantissa >>= 1
exp += 1
}
}
}
mantissa >>= 1
f = T(math.ldexp(f64(mantissa), i32(exp-MSIZE1)))
if math.is_inf(f, 0) {
exact = false
}
return
}
rat_compare :: proc(x, y: ^Rat, allocator := context.allocator) -> (comparison: int, error: Error) {
assert_if_nil(x, y)
context.allocator = allocator
a, b: Int
internal_init_multi(&a, &b) or_return
defer internal_destroy(&a, &b)
internal_int_scale_denom(&a, &x.a, &y.b) or_return
internal_int_scale_denom(&b, &y.a, &x.b) or_return
return int_compare(&a, &b)
}
rat_add_int :: proc(dst, x: ^Rat, y: ^Int, allocator := context.allocator) -> (err: Error) {
assert_if_nil(dst, x)
assert_if_nil(y)
z: Rat
rat_set_int(&z, y, allocator) or_return
defer internal_destroy(&z)
return rat_add_rat(dst, x, &z, allocator)
}
rat_sub_int :: proc(dst, x: ^Rat, y: ^Int, allocator := context.allocator) -> (err: Error) {
assert_if_nil(dst, x)
assert_if_nil(y)
z: Rat
rat_set_int(&z, y, allocator) or_return
defer internal_destroy(&z)
return rat_sub_rat(dst, x, &z, allocator)
}
rat_mul_int :: proc(dst, x: ^Rat, y: ^Int, allocator := context.allocator) -> (err: Error) {
assert_if_nil(dst, x)
assert_if_nil(y)
z: Rat
rat_set_int(&z, y, allocator) or_return
defer internal_destroy(&z)
return rat_mul_rat(dst, x, &z, allocator)
}
rat_div_int :: proc(dst, x: ^Rat, y: ^Int, allocator := context.allocator) -> (err: Error) {
if internal_is_zero(y) {
return .Division_by_Zero
}
z: Rat
rat_set_int(&z, y, allocator) or_return
defer internal_destroy(&z)
return rat_div_rat(dst, x, &z, allocator)
}
int_add_rat :: proc(dst: ^Rat, x: ^Int, y: ^Rat, allocator := context.allocator) -> (err: Error) {
assert_if_nil(x)
assert_if_nil(dst, y)
w: Rat
rat_set_int(&w, x, allocator) or_return
defer internal_destroy(&w)
return rat_add_rat(dst, &w, y, allocator)
}
int_sub_rat :: proc(dst: ^Rat, x: ^Int, y: ^Rat, allocator := context.allocator) -> (err: Error) {
assert_if_nil(x)
assert_if_nil(dst, y)
w: Rat
rat_set_int(&w, x, allocator) or_return
defer internal_destroy(&w)
return rat_sub_rat(dst, &w, y, allocator)
}
int_mul_rat :: proc(dst: ^Rat, x: ^Int, y: ^Rat, allocator := context.allocator) -> (err: Error) {
assert_if_nil(x)
assert_if_nil(dst, y)
w: Rat
rat_set_int(&w, x, allocator) or_return
defer internal_destroy(&w)
return rat_mul_rat(dst, &w, y, allocator)
}
int_div_rat :: proc(dst: ^Rat, x: ^Int, y: ^Rat, allocator := context.allocator) -> (err: Error) {
if internal_is_zero(y) {
return .Division_by_Zero
}
w: Rat
rat_set_int(&w, x, allocator) or_return
defer internal_destroy(&w)
return rat_div_rat(dst, &w, y, allocator)
}

View File

@@ -147,55 +147,53 @@ len :: proc{len_u8, len_u16, len_u32, len_u64, len_uint}
add_u32 :: proc(x, y, carry: u32) -> (sum, carry_out: u32) {
yc := y + carry
sum = x + yc
if sum < x || yc < y {
carry_out = 1
}
tmp_carry, tmp_carry2: bool
sum, tmp_carry = intrinsics.overflow_add(x, y)
sum, tmp_carry2 = intrinsics.overflow_add(sum, carry)
carry_out = u32(tmp_carry | tmp_carry2)
return
}
add_u64 :: proc(x, y, carry: u64) -> (sum, carry_out: u64) {
yc := y + carry
sum = x + yc
if sum < x || yc < y {
carry_out = 1
}
tmp_carry, tmp_carry2: bool
sum, tmp_carry = intrinsics.overflow_add(x, y)
sum, tmp_carry2 = intrinsics.overflow_add(sum, carry)
carry_out = u64(tmp_carry | tmp_carry2)
return
}
add_uint :: proc(x, y, carry: uint) -> (sum, carry_out: uint) {
yc := y + carry
sum = x + yc
if sum < x || yc < y {
carry_out = 1
when size_of(uint) == size_of(u64) {
a, b := add_u64(u64(x), u64(y), u64(carry))
} else {
#assert(size_of(uint) == size_of(u32))
a, b := add_u32(u32(x), u32(y), u32(carry))
}
return
return uint(a), uint(b)
}
add :: proc{add_u32, add_u64, add_uint}
sub_u32 :: proc(x, y, borrow: u32) -> (diff, borrow_out: u32) {
yb := y + borrow
diff = x - yb
if diff > x || yb < y {
borrow_out = 1
}
tmp_borrow, tmp_borrow2: bool
diff, tmp_borrow = intrinsics.overflow_sub(x, y)
diff, tmp_borrow2 = intrinsics.overflow_sub(diff, borrow)
borrow_out = u32(tmp_borrow | tmp_borrow2)
return
}
sub_u64 :: proc(x, y, borrow: u64) -> (diff, borrow_out: u64) {
yb := y + borrow
diff = x - yb
if diff > x || yb < y {
borrow_out = 1
}
tmp_borrow, tmp_borrow2: bool
diff, tmp_borrow = intrinsics.overflow_sub(x, y)
diff, tmp_borrow2 = intrinsics.overflow_sub(diff, borrow)
borrow_out = u64(tmp_borrow | tmp_borrow2)
return
}
sub_uint :: proc(x, y, borrow: uint) -> (diff, borrow_out: uint) {
yb := y + borrow
diff = x - yb
if diff > x || yb < y {
borrow_out = 1
when size_of(uint) == size_of(u64) {
a, b := sub_u64(u64(x), u64(y), u64(borrow))
} else {
#assert(size_of(uint) == size_of(u32))
a, b := sub_u32(u32(x), u32(y), u32(borrow))
}
return
return uint(a), uint(b)
}
sub :: proc{sub_u32, sub_u64, sub_uint}
@@ -206,18 +204,8 @@ mul_u32 :: proc(x, y: u32) -> (hi, lo: u32) {
return
}
mul_u64 :: proc(x, y: u64) -> (hi, lo: u64) {
mask :: 1<<32 - 1
x0, x1 := x & mask, x >> 32
y0, y1 := y & mask, y >> 32
w0 := x0 * y0
t := x1*y0 + w0>>32
w1, w2 := t & mask, t >> 32
w1 += x0 * y1
hi = x1*y1 + w2 + w1>>32
lo = x * y
prod_wide := u128(x) * u128(y)
hi, lo = u64(prod_wide>>64), u64(prod_wide)
return
}

View File

@@ -224,6 +224,15 @@ Slice_Expr :: struct {
close: tokenizer.Pos,
}
Matrix_Index_Expr :: struct {
using node: Expr,
expr: ^Expr,
open: tokenizer.Pos,
row_index: ^Expr,
column_index: ^Expr,
close: tokenizer.Pos,
}
Call_Expr :: struct {
using node: Expr,
inlining: Proc_Inlining,
@@ -739,3 +748,11 @@ Relative_Type :: struct {
tag: ^Expr,
type: ^Expr,
}
Matrix_Type :: struct {
using node: Expr,
tok_pos: tokenizer.Pos,
row_count: ^Expr,
column_count: ^Expr,
elem: ^Expr,
}

View File

@@ -117,6 +117,10 @@ clone_node :: proc(node: ^Node) -> ^Node {
case Index_Expr:
r.expr = clone(r.expr)
r.index = clone(r.index)
case Matrix_Index_Expr:
r.expr = clone(r.expr)
r.row_index = clone(r.row_index)
r.column_index = clone(r.column_index)
case Deref_Expr:
r.expr = clone(r.expr)
case Slice_Expr:
@@ -275,7 +279,10 @@ clone_node :: proc(node: ^Node) -> ^Node {
case Map_Type:
r.key = clone(r.key)
r.value = clone(r.value)
case Matrix_Type:
r.row_count = clone(r.row_count)
r.column_count = clone(r.column_count)
r.elem = clone(r.elem)
case:
fmt.panicf("Unhandled node kind: %T", r)
}

View File

@@ -110,6 +110,10 @@ walk :: proc(v: ^Visitor, node: ^Node) {
case Index_Expr:
walk(v, n.expr)
walk(v, n.index)
case Matrix_Index_Expr:
walk(v, n.expr)
walk(v, n.row_index)
walk(v, n.column_index)
case Deref_Expr:
walk(v, n.expr)
case Slice_Expr:
@@ -398,6 +402,10 @@ walk :: proc(v: ^Visitor, node: ^Node) {
case Relative_Type:
walk(v, n.tag)
walk(v, n.type)
case Matrix_Type:
walk(v, n.row_count)
walk(v, n.column_count)
walk(v, n.elem)
case:
fmt.panicf("ast.walk: unexpected node type %T", n)

View File

@@ -10,7 +10,7 @@ Array :: struct($T: typeid) {
String :: distinct Array(byte)
Version_Type_Major :: 0
Version_Type_Minor :: 1
Version_Type_Minor :: 2
Version_Type_Patch :: 0
Version_Type :: struct {
@@ -101,17 +101,19 @@ Entity_Flag :: enum u32le {
Param_Ellipsis = 5, // Variadic parameter
Param_CVararg = 6, // #c_vararg
Param_No_Alias = 7, // #no_alias
Param_Any_Int = 8, // #any_int
Type_Alias = 8,
Type_Alias = 20,
Var_Thread_Local = 9,
Var_Static = 10,
Var_Thread_Local = 40,
Var_Static = 41,
}
Entity_Flags :: distinct bit_set[Entity_Flag; u32le]
Entity_Flags :: distinct bit_set[Entity_Flag; u64le]
Entity :: struct {
kind: Entity_Kind,
_: u32le, // reserved
flags: Entity_Flags,
pos: Position,
name: String,
@@ -167,6 +169,7 @@ Type_Kind :: enum u32le {
Relative_Pointer = 20,
Relative_Slice = 21,
Multi_Pointer = 22,
Matrix = 23,
}
Type_Elems_Cap :: 4
@@ -192,11 +195,12 @@ Type :: struct {
custom_align: String,
// Used by:
// .Array - 1 count: 0=len
// .Array - 1 count: 0=len
// .Enumerated_Array - 1 count: 0=len
// .SOA_Struct_Fixed - 1 count: 0=len
// .Bit_Set - 2 count: 0=lower, 1=upper
// .Simd_Vector - 1 count: 0=len
// .Bit_Set - 2 count: 0=lower, 1=upper
// .Simd_Vector - 1 count: 0=len
// .Matrix - 2 count: 0=row_count, 1=column_count
elem_count_len: u32le,
elem_counts: [Type_Elems_Cap]i64le,
@@ -224,6 +228,7 @@ Type :: struct {
// .Relative_Pointer - 2 types: 0=pointer type, 1=base integer
// .Relative_Slice - 2 types: 0=slice type, 1=base integer
// .Multi_Pointer - 1 type: 0=element
// .Matrix - 1 type: 0=element
types: Array(Type_Index),
// Used by:

View File

@@ -2703,6 +2703,22 @@ parse_operand :: proc(p: ^Parser, lhs: bool) -> ^ast.Expr {
bst.underlying = underlying
bst.close = close.pos
return bst
case .Matrix:
tok := expect_token(p, .Matrix)
expect_token(p, .Open_Bracket)
row_count := parse_expr(p, false)
expect_token(p, .Comma)
column_count := parse_expr(p, false)
expect_token(p, .Close_Bracket)
elem := parse_type(p)
mt := ast.new(ast.Matrix_Type, tok.pos, elem.end)
mt.tok_pos = tok.pos
mt.row_count = row_count
mt.column_count = column_count
mt.elem = elem
return mt
case .Asm:
tok := expect_token(p, .Asm)
@@ -2969,7 +2985,7 @@ parse_atom_expr :: proc(p: ^Parser, value: ^ast.Expr, lhs: bool) -> (operand: ^a
defer p.allow_range = prev_allow_range
p.allow_range = false
indicies: [2]^ast.Expr
indices: [2]^ast.Expr
interval: tokenizer.Token
is_slice_op := false
@@ -2981,18 +2997,18 @@ parse_atom_expr :: proc(p: ^Parser, value: ^ast.Expr, lhs: bool) -> (operand: ^a
// NOTE(bill): Do not err yet
break
case:
indicies[0] = parse_expr(p, false)
indices[0] = parse_expr(p, false)
}
#partial switch p.curr_tok.kind {
case .Ellipsis, .Range_Half, .Range_Full:
error(p, p.curr_tok.pos, "expected a colon, not a range")
fallthrough
case .Colon:
case .Colon, .Comma/*matrix index*/:
interval = advance_token(p)
is_slice_op = true
if p.curr_tok.kind != .Close_Bracket && p.curr_tok.kind != .EOF {
indicies[1] = parse_expr(p, false)
indices[1] = parse_expr(p, false)
}
}
@@ -3000,20 +3016,34 @@ parse_atom_expr :: proc(p: ^Parser, value: ^ast.Expr, lhs: bool) -> (operand: ^a
p.expr_level -= 1
if is_slice_op {
se := ast.new(ast.Slice_Expr, operand.pos, end_pos(close))
se.expr = operand
se.open = open.pos
se.low = indicies[0]
se.interval = interval
se.high = indicies[1]
se.close = close.pos
if interval.kind == .Comma {
if indices[0] == nil || indices[1] == nil {
error(p, p.curr_tok.pos, "matrix index expressions require both row and column indices")
}
se := ast.new(ast.Matrix_Index_Expr, operand.pos, end_pos(close))
se.expr = operand
se.open = open.pos
se.row_index = indices[0]
se.column_index = indices[1]
se.close = close.pos
operand = se
operand = se
} else {
se := ast.new(ast.Slice_Expr, operand.pos, end_pos(close))
se.expr = operand
se.open = open.pos
se.low = indices[0]
se.interval = interval
se.high = indices[1]
se.close = close.pos
operand = se
}
} else {
ie := ast.new(ast.Index_Expr, operand.pos, end_pos(close))
ie.expr = operand
ie.open = open.pos
ie.index = indicies[0]
ie.index = indices[0]
ie.close = close.pos
operand = ie

View File

@@ -150,6 +150,7 @@ Token_Kind :: enum u32 {
Asm, // asm
Inline, // inline
No_Inline, // no_inline
Matrix, // matrix
B_Keyword_End,
COUNT,
@@ -280,6 +281,7 @@ tokens := [Token_Kind.COUNT]string {
"asm",
"inline",
"no_inline",
"matrix",
"",
}
@@ -299,10 +301,10 @@ token_to_string :: proc(tok: Token) -> string {
}
to_string :: proc(kind: Token_Kind) -> string {
if Token_Kind.Invalid <= kind && kind < Token_Kind.COUNT {
if .Invalid <= kind && kind < .COUNT {
return tokens[kind]
}
if Token_Kind.B_Custom_Keyword_Begin < kind {
if .B_Custom_Keyword_Begin < kind {
n := int(u16(kind)-u16(Token_Kind.B_Custom_Keyword_Begin))
if n < len(custom_keyword_tokens) {
return custom_keyword_tokens[n]
@@ -313,7 +315,7 @@ to_string :: proc(kind: Token_Kind) -> string {
}
is_literal :: proc(kind: Token_Kind) -> bool {
return Token_Kind.B_Literal_Begin < kind && kind < Token_Kind.B_Literal_End
return .B_Literal_Begin < kind && kind < .B_Literal_End
}
is_operator :: proc(kind: Token_Kind) -> bool {
#partial switch kind {
@@ -327,13 +329,13 @@ is_operator :: proc(kind: Token_Kind) -> bool {
return false
}
is_assignment_operator :: proc(kind: Token_Kind) -> bool {
return Token_Kind.B_Assign_Op_Begin < kind && kind < Token_Kind.B_Assign_Op_End || kind == Token_Kind.Eq
return .B_Assign_Op_Begin < kind && kind < .B_Assign_Op_End || kind == .Eq
}
is_keyword :: proc(kind: Token_Kind) -> bool {
switch {
case Token_Kind.B_Keyword_Begin < kind && kind < Token_Kind.B_Keyword_End:
case .B_Keyword_Begin < kind && kind < .B_Keyword_End:
return true
case Token_Kind.B_Custom_Keyword_Begin < kind:
case .B_Custom_Keyword_Begin < kind:
return true
}
return false

View File

@@ -43,6 +43,36 @@ Weekday :: enum int {
Saturday,
}
Stopwatch :: struct {
running: bool,
_start_time: Tick,
_accumulation: Duration,
}
stopwatch_start :: proc(using stopwatch: ^Stopwatch) {
if !running {
_start_time = tick_now()
running = true
}
}
stopwatch_stop :: proc(using stopwatch: ^Stopwatch) {
if running {
_accumulation += tick_diff(_start_time, tick_now())
running = false
}
}
stopwatch_reset :: proc(using stopwatch: ^Stopwatch) {
_accumulation = {}
running = false
}
stopwatch_duration :: proc(using stopwatch: Stopwatch) -> Duration {
if !running { return _accumulation }
return _accumulation + tick_diff(_start_time, tick_now())
}
diff :: proc(start, end: Time) -> Duration {
d := end._nsec - start._nsec
return Duration(d)
@@ -52,7 +82,6 @@ since :: proc(start: Time) -> Duration {
return diff(start, now())
}
duration_nanoseconds :: proc(d: Duration) -> i64 {
return i64(d)
}
@@ -106,6 +135,7 @@ duration_round :: proc(d, m: Duration) -> Duration {
}
return MAX_DURATION
}
duration_truncate :: proc(d, m: Duration) -> Duration {
return d if m <= 0 else d - d%m
}
@@ -119,17 +149,33 @@ year :: proc(t: Time) -> (year: int) {
year, _, _, _ = _date(t, true)
return
}
month :: proc(t: Time) -> (month: Month) {
_, month, _, _ = _date(t, true)
return
}
day :: proc(t: Time) -> (day: int) {
_, _, day, _ = _date(t, true)
return
}
clock :: proc(t: Time) -> (hour, min, sec: int) {
sec = int(_time_abs(t) % SECONDS_PER_DAY)
clock :: proc { clock_from_time, clock_from_duration, clock_from_stopwatch }
clock_from_time :: proc(t: Time) -> (hour, min, sec: int) {
return clock_from_seconds(_time_abs(t))
}
clock_from_duration :: proc(d: Duration) -> (hour, min, sec: int) {
return clock_from_seconds(u64(d/1e9))
}
clock_from_stopwatch :: proc(s: Stopwatch) -> (hour, min, sec: int) {
return clock_from_duration(stopwatch_duration(s))
}
clock_from_seconds :: proc(nsec: u64) -> (hour, min, sec: int) {
sec = int(nsec % SECONDS_PER_DAY)
hour = sec / SECONDS_PER_HOUR
sec -= hour * SECONDS_PER_HOUR
min = sec / SECONDS_PER_MINUTE
@@ -137,12 +183,10 @@ clock :: proc(t: Time) -> (hour, min, sec: int) {
return
}
read_cycle_counter :: proc() -> u64 {
return u64(intrinsics.read_cycle_counter())
}
unix :: proc(sec: i64, nsec: i64) -> Time {
sec, nsec := sec, nsec
if nsec < 0 || nsec >= 1e9 {

View File

@@ -2203,6 +2203,215 @@ arbitrary_precision_maths :: proc() {
print_bigint("\nLCM of random prime A and random number B (in base 36): ", d, 36)
}
matrix_type :: proc() {
fmt.println("\n# matrix type")
// A matrix is a mathematical type built into Odin. It is a regular array of numbers,
// arranged in rows and columns
{
// The following represents a matrix that has 2 rows and 3 columns
m: matrix[2, 3]f32
m = matrix[2, 3]f32{
1, 9, -13,
20, 5, -6,
}
// Element types of integers, float, and complex numbers are supported by matrices.
// There is no support for booleans, quaternions, or any compound type.
// Indexing a matrix can be used with the matrix indexing syntax
// This mirrors othe type usages: type on the left, usage on the right
elem := m[1, 2] // row 1, column 2
assert(elem == -6)
// Scalars act as if they are scaled identity matrices
// and can be assigned to matrices as them
b := matrix[2, 2]f32{}
f := f32(3)
b = f
fmt.println("b", b)
fmt.println("b == f", b == f)
}
{ // Matrices support multiplication between matrices
a := matrix[2, 3]f32{
2, 3, 1,
4, 5, 0,
}
b := matrix[3, 2]f32{
1, 2,
3, 4,
5, 6,
}
fmt.println("a", a)
fmt.println("b", b)
c := a * b
#assert(type_of(c) == matrix[2, 2]f32)
fmt.tprintln("c = a * b", c)
}
{ // Matrices support multiplication between matrices and arrays
m := matrix[4, 4]f32{
1, 2, 3, 4,
5, 5, 4, 2,
0, 1, 3, 0,
0, 1, 4, 1,
}
v := [4]f32{1, 5, 4, 3}
// treating 'v' as a column vector
fmt.println("m * v", m * v)
// treating 'v' as a row vector
fmt.println("v * m", v * m)
// Support with non-square matrices
s := matrix[2, 4]f32{ // [4][2]f32
2, 4, 3, 1,
7, 8, 6, 5,
}
w := [2]f32{1, 2}
r: [4]f32 = w * s
fmt.println("r", r)
}
{ // Component-wise operations
// if the element type supports it
// Not support for '/', '%', or '%%' operations
a := matrix[2, 2]i32{
1, 2,
3, 4,
}
b := matrix[2, 2]i32{
-5, 1,
9, -7,
}
c0 := a + b
c1 := a - b
c2 := a & b
c3 := a | b
c4 := a ~ b
c5 := a &~ b
// component-wise multiplication
// since a * b would be a standard matrix multiplication
c6 := hadamard_product(a, b)
fmt.println("a + b", c0)
fmt.println("a - b", c1)
fmt.println("a & b", c2)
fmt.println("a | b", c3)
fmt.println("a ~ b", c4)
fmt.println("a &~ b", c5)
fmt.println("hadamard_product(a, b)", c6)
}
{ // Submatrix casting square matrices
// Casting a square matrix to another square matrix with same element type
// is supported.
// If the cast is to a smaller matrix type, the top-left submatrix is taken.
// If the cast is to a larger matrix type, the matrix is extended with zeros
// everywhere and ones in the diagonal for the unfilled elements of the
// extended matrix.
mat2 :: distinct matrix[2, 2]f32
mat4 :: distinct matrix[4, 4]f32
m2 := mat2{
1, 3,
2, 4,
}
m4 := mat4(m2)
assert(m4[2, 2] == 1)
assert(m4[3, 3] == 1)
fmt.println("m2", m2)
fmt.println("m4", m4)
fmt.println("mat2(m4)", mat2(m4))
assert(mat2(m4) == m2)
}
{ // Casting non-square matrices
// Casting a matrix to another matrix is allowed as long as they share
// the same element type and the number of elements (rows*columns).
// Matrices in Odin are stored in column-major order, which means
// the casts will preserve this element order.
mat2x4 :: distinct matrix[2, 4]f32
mat4x2 :: distinct matrix[4, 2]f32
x := mat2x4{
1, 3, 5, 7,
2, 4, 6, 8,
}
y := mat4x2(x)
fmt.println("x", x)
fmt.println("y", y)
}
// TECHNICAL INFORMATION: the internal representation of a matrix in Odin is stored
// in column-major format
// e.g. matrix[2, 3]f32 is internally [3][2]f32 (with different a alignment requirement)
// Column-major is used in order to utilize (SIMD) vector instructions effectively on
// modern hardware, if possible.
//
// Unlike normal arrays, matrices try to maximize alignment to allow for the (SIMD) vectorization
// properties whilst keeping zero padding (either between columns or at the end of the type).
//
// Zero padding is a compromise for use with third-party libraries, instead of optimizing for performance.
// Padding between columns was not taken even if that would have allowed each column to be loaded
// individually into a SIMD register with the correct alignment properties.
//
// Currently, matrices are limited to a maximum of 16 elements (rows*columns), and a minimum of 1 element.
// This is because matrices are stored as values (not a reference type), and thus operations on them will
// be stored on the stack. Restricting the maximum element count minimizing the possibility of stack overflows.
// Built-in Procedures (Compiler Level)
// transpose(m)
// transposes a matrix
// outer_product(a, b)
// takes two array-like data types and returns the outer product
// of the values in a matrix
// hadamard_product(a, b)
// component-wise multiplication of two matrices of the same type
// matrix_flatten(m)
// converts the matrix into a flatten array of elements
// in column-major order
// Example:
// m := matrix[2, 2]f32{
// x0, x1,
// y0, y1,
// }
// array: [4]f32 = matrix_flatten(m)
// assert(array == {x0, y0, x1, y1})
// conj(x)
// conjugates the elements of a matrix for complex element types only
// Built-in Procedures (Runtime Level) (all square matrix procedures)
// determinant(m)
// adjugate(m)
// inverse(m)
// inverse_transpose(m)
// hermitian_adjoint(m)
// matrix_trace(m)
// matrix_minor(m)
}
main :: proc() {
when true {
the_basics()
@@ -2238,5 +2447,6 @@ main :: proc() {
or_else_operator()
or_return_operator()
arbitrary_precision_maths()
matrix_type()
}
}

View File

@@ -443,7 +443,17 @@ u64 ceil_log2(u64 x) {
return cast(u64)(bit_set_count(x) - 1 - y);
}
u32 prev_pow2(u32 n) {
if (n == 0) {
return 0;
}
n |= n >> 1;
n |= n >> 2;
n |= n >> 4;
n |= n >> 8;
n |= n >> 16;
return n - (n >> 1);
}
i32 prev_pow2(i32 n) {
if (n <= 0) {
return 0;

View File

@@ -14,7 +14,7 @@ struct OdinDocVersionType {
};
#define OdinDocVersionType_Major 0
#define OdinDocVersionType_Minor 1
#define OdinDocVersionType_Minor 2
#define OdinDocVersionType_Patch 0
struct OdinDocHeaderBase {
@@ -82,6 +82,7 @@ enum OdinDocTypeKind : u32 {
OdinDocType_RelativePointer = 20,
OdinDocType_RelativeSlice = 21,
OdinDocType_MultiPointer = 22,
OdinDocType_Matrix = 23,
};
enum OdinDocTypeFlag_Basic : u32 {
@@ -154,21 +155,22 @@ enum OdinDocEntityKind : u32 {
OdinDocEntity_LibraryName = 7,
};
enum OdinDocEntityFlag : u32 {
OdinDocEntityFlag_Foreign = 1<<0,
OdinDocEntityFlag_Export = 1<<1,
enum OdinDocEntityFlag : u64 {
OdinDocEntityFlag_Foreign = 1ull<<0,
OdinDocEntityFlag_Export = 1ull<<1,
OdinDocEntityFlag_Param_Using = 1<<2,
OdinDocEntityFlag_Param_Const = 1<<3,
OdinDocEntityFlag_Param_AutoCast = 1<<4,
OdinDocEntityFlag_Param_Ellipsis = 1<<5,
OdinDocEntityFlag_Param_CVararg = 1<<6,
OdinDocEntityFlag_Param_NoAlias = 1<<7,
OdinDocEntityFlag_Param_Using = 1ull<<2,
OdinDocEntityFlag_Param_Const = 1ull<<3,
OdinDocEntityFlag_Param_AutoCast = 1ull<<4,
OdinDocEntityFlag_Param_Ellipsis = 1ull<<5,
OdinDocEntityFlag_Param_CVararg = 1ull<<6,
OdinDocEntityFlag_Param_NoAlias = 1ull<<7,
OdinDocEntityFlag_Param_AnyInt = 1ull<<8,
OdinDocEntityFlag_Type_Alias = 1<<8,
OdinDocEntityFlag_Type_Alias = 1ull<<20,
OdinDocEntityFlag_Var_Thread_Local = 1<<9,
OdinDocEntityFlag_Var_Static = 1<<10,
OdinDocEntityFlag_Var_Thread_Local = 1ull<<40,
OdinDocEntityFlag_Var_Static = 1ull<<41,
};
struct OdinDocEntity {

View File

@@ -756,6 +756,14 @@ OdinDocTypeIndex odin_doc_type(OdinDocWriter *w, Type *type) {
doc_type.types = odin_write_slice(w, types, gb_count_of(types));
}
break;
case Type_Matrix:
doc_type.kind = OdinDocType_Matrix;
doc_type.elem_count_len = 2;
doc_type.elem_counts[0] = type->Matrix.row_count;
doc_type.elem_counts[1] = type->Matrix.column_count;
doc_type.types = odin_doc_type_as_slice(w, type->Matrix.elem);
break;
}
if (dst) {
@@ -842,6 +850,7 @@ OdinDocEntityIndex odin_doc_add_entity(OdinDocWriter *w, Entity *e) {
if (e->flags & EntityFlag_AutoCast) { flags |= OdinDocEntityFlag_Param_AutoCast; }
if (e->flags & EntityFlag_Ellipsis) { flags |= OdinDocEntityFlag_Param_Ellipsis; }
if (e->flags & EntityFlag_NoAlias) { flags |= OdinDocEntityFlag_Param_NoAlias; }
if (e->flags & EntityFlag_AnyInt) { flags |= OdinDocEntityFlag_Param_AnyInt; }
}
OdinDocString init_string = {};

View File

@@ -437,6 +437,20 @@ LLVMMetadataRef lb_debug_type_internal(lbModule *m, Type *type) {
gbString name = type_to_string(type, temporary_allocator());
return LLVMDIBuilderCreateStructType(m->debug_builder, nullptr, name, gb_string_length(name), nullptr, 0, 2*word_bits, word_bits, LLVMDIFlagZero, nullptr, elements, element_count, 0, nullptr, "", 0);
}
case Type_Matrix: {
LLVMMetadataRef subscripts[1] = {};
subscripts[0] = LLVMDIBuilderGetOrCreateSubrange(m->debug_builder,
0ll,
matrix_type_total_internal_elems(type)
);
return LLVMDIBuilderCreateArrayType(m->debug_builder,
8*cast(uint64_t)type_size_of(type),
8*cast(unsigned)type_align_of(type),
lb_debug_type(m, type->Matrix.elem),
subscripts, gb_count_of(subscripts));
}
}
GB_PANIC("Invalid type %s", type_to_string(type));

View File

@@ -1563,15 +1563,61 @@ LLVMValueRef llvm_vector_broadcast(lbProcedure *p, LLVMValueRef value, unsigned
return LLVMBuildShuffleVector(p->builder, single, LLVMGetUndef(LLVMTypeOf(single)), mask, "");
}
LLVMValueRef llvm_vector_shuffle_reduction(lbProcedure *p, LLVMValueRef value, LLVMOpcode op_code) {
LLVMTypeRef original_vector_type = LLVMTypeOf(value);
GB_ASSERT(LLVMGetTypeKind(original_vector_type) == LLVMVectorTypeKind);
unsigned len = LLVMGetVectorSize(original_vector_type);
LLVMValueRef v_zero32 = lb_const_int(p->module, t_u32, 0).value;
if (len == 1) {
return LLVMBuildExtractElement(p->builder, value, v_zero32, "");
}
GB_ASSERT((len & (len-1)) == 0);
for (unsigned i = len; i != 1; i >>= 1) {
unsigned mask_len = i/2;
LLVMValueRef lhs_mask = llvm_mask_iota(p->module, 0, mask_len);
LLVMValueRef rhs_mask = llvm_mask_iota(p->module, mask_len, mask_len);
GB_ASSERT(LLVMTypeOf(lhs_mask) == LLVMTypeOf(rhs_mask));
LLVMValueRef lhs = LLVMBuildShuffleVector(p->builder, value, LLVMGetUndef(LLVMTypeOf(value)), lhs_mask, "");
LLVMValueRef rhs = LLVMBuildShuffleVector(p->builder, value, LLVMGetUndef(LLVMTypeOf(value)), rhs_mask, "");
GB_ASSERT(LLVMTypeOf(lhs) == LLVMTypeOf(rhs));
value = LLVMBuildBinOp(p->builder, op_code, lhs, rhs, "");
}
return LLVMBuildExtractElement(p->builder, value, v_zero32, "");
}
LLVMValueRef llvm_vector_expand_to_power_of_two(lbProcedure *p, LLVMValueRef value) {
LLVMTypeRef vector_type = LLVMTypeOf(value);
unsigned len = LLVMGetVectorSize(vector_type);
if (len == 1) {
return value;
}
if ((len & (len-1)) == 0) {
return value;
}
unsigned expanded_len = cast(unsigned)next_pow2(cast(i64)len);
LLVMValueRef mask = llvm_mask_iota(p->module, 0, expanded_len);
return LLVMBuildShuffleVector(p->builder, value, LLVMConstNull(vector_type), mask, "");
}
LLVMValueRef llvm_vector_reduce_add(lbProcedure *p, LLVMValueRef value) {
LLVMTypeRef type = LLVMTypeOf(value);
GB_ASSERT(LLVMGetTypeKind(type) == LLVMVectorTypeKind);
LLVMTypeRef elem = LLVMGetElementType(type);
unsigned len = LLVMGetVectorSize(type);
if (len == 0) {
return LLVMConstNull(type);
}
char const *name = nullptr;
i32 value_offset = 0;
i32 value_count = 0;
switch (LLVMGetTypeKind(elem)) {
case LLVMHalfTypeKind:
case LLVMFloatTypeKind:
@@ -1589,19 +1635,56 @@ LLVMValueRef llvm_vector_reduce_add(lbProcedure *p, LLVMValueRef value) {
GB_PANIC("invalid vector type %s", LLVMPrintTypeToString(type));
break;
}
unsigned id = LLVMLookupIntrinsicID(name, gb_strlen(name));
GB_ASSERT_MSG(id != 0, "Unable to find %s", name);
LLVMTypeRef types[1] = {};
types[0] = type;
LLVMValueRef ip = LLVMGetIntrinsicDeclaration(p->module->mod, id, types, gb_count_of(types));
LLVMValueRef values[2] = {};
values[0] = LLVMConstNull(elem);
values[1] = value;
LLVMValueRef call = LLVMBuildCall(p->builder, ip, values+value_offset, value_count, "");
return call;
if (id != 0 && false) {
LLVMTypeRef types[1] = {};
types[0] = type;
LLVMValueRef ip = LLVMGetIntrinsicDeclaration(p->module->mod, id, types, gb_count_of(types));
LLVMValueRef values[2] = {};
values[0] = LLVMConstNull(elem);
values[1] = value;
LLVMValueRef call = LLVMBuildCall(p->builder, ip, values+value_offset, value_count, "");
return call;
}
// Manual reduce
#if 0
LLVMValueRef sum = LLVMBuildExtractElement(p->builder, value, lb_const_int(p->module, t_u32, 0).value, "");
for (unsigned i = 0; i < len; i++) {
LLVMValueRef val = LLVMBuildExtractElement(p->builder, value, lb_const_int(p->module, t_u32, i).value, "");
if (LLVMGetTypeKind(elem) == LLVMIntegerTypeKind) {
sum = LLVMBuildAdd(p->builder, sum, val, "");
} else {
sum = LLVMBuildFAdd(p->builder, sum, val, "");
}
}
return sum;
#else
LLVMOpcode op_code = LLVMFAdd;
if (LLVMGetTypeKind(elem) == LLVMIntegerTypeKind) {
op_code = LLVMAdd;
}
unsigned len_pow_2 = prev_pow2(len);
if (len_pow_2 == len) {
return llvm_vector_shuffle_reduction(p, value, op_code);
} else {
GB_ASSERT(len_pow_2 < len);
LLVMValueRef lower_mask = llvm_mask_iota(p->module, 0, len_pow_2);
LLVMValueRef upper_mask = llvm_mask_iota(p->module, len_pow_2, len-len_pow_2);
LLVMValueRef lower = LLVMBuildShuffleVector(p->builder, value, LLVMGetUndef(LLVMTypeOf(value)), lower_mask, "");
LLVMValueRef upper = LLVMBuildShuffleVector(p->builder, value, LLVMGetUndef(LLVMTypeOf(value)), upper_mask, "");
upper = llvm_vector_expand_to_power_of_two(p, upper);
LLVMValueRef lower_reduced = llvm_vector_shuffle_reduction(p, lower, op_code);
LLVMValueRef upper_reduced = llvm_vector_shuffle_reduction(p, upper, op_code);
GB_ASSERT(LLVMTypeOf(lower_reduced) == LLVMTypeOf(upper_reduced));
return LLVMBuildBinOp(p->builder, op_code, lower_reduced, upper_reduced, "");
}
#endif
}
LLVMValueRef llvm_vector_add(lbProcedure *p, LLVMValueRef a, LLVMValueRef b) {