diff options
| author | Wes Hardee <weshardee@gmail.com> | 2021-12-18 12:43:33 -0600 |
|---|---|---|
| committer | Wes Hardee <weshardee@gmail.com> | 2021-12-18 12:43:33 -0600 |
| commit | 92ce7defb12436b81eb1f2c19fa1e01be4a8ead3 (patch) | |
| tree | 75a9b9c9ad10d7a2b39b05afba2fd88a7a185f0f | |
| parent | a48317deee95b956430ace83f0db3e34bef590dd (diff) | |
| parent | 0548db423067bce16d45af651819bf56feb5d411 (diff) | |
Merge branch 'master' of https://github.com/weshardee/Odin
| -rw-r--r-- | core/bytes/bytes.odin | 2 | ||||
| -rw-r--r-- | core/math/big/common.odin | 23 | ||||
| -rw-r--r-- | core/math/big/internal.odin | 168 | ||||
| -rw-r--r-- | core/math/big/logical.odin | 33 | ||||
| -rw-r--r-- | core/math/big/private.odin | 118 | ||||
| -rw-r--r-- | core/math/big/rat.odin | 10 | ||||
| -rw-r--r-- | core/math/math.odin | 1 | ||||
| -rw-r--r-- | core/runtime/internal.odin | 14 | ||||
| -rw-r--r-- | core/runtime/procs_wasm32.odin | 41 | ||||
| -rw-r--r-- | core/strconv/strconv.odin | 4 | ||||
| -rw-r--r-- | core/strings/strings.odin | 6 | ||||
| -rw-r--r-- | src/check_stmt.cpp | 7 | ||||
| -rw-r--r-- | src/llvm_backend_opt.cpp | 26 | ||||
| -rw-r--r-- | tests/core/math/big/test.odin | 8 | ||||
| -rw-r--r-- | tests/core/math/big/test.py | 59 | ||||
| -rw-r--r-- | vendor/wasm/WebGL/runtime.js | 10 |
16 files changed, 295 insertions, 235 deletions
diff --git a/core/bytes/bytes.odin b/core/bytes/bytes.odin index cbc1e2506..1e83b93c8 100644 --- a/core/bytes/bytes.odin +++ b/core/bytes/bytes.odin @@ -1143,7 +1143,7 @@ fields_proc :: proc(s: []byte, f: proc(rune) -> bool, allocator := context.alloc } if start >= 0 { - append(&subslices, s[start : end]) + append(&subslices, s[start : len(s)]) } return subslices[:] diff --git a/core/math/big/common.odin b/core/math/big/common.odin index 5b7d162bc..31ad54b14 100644 --- a/core/math/big/common.odin +++ b/core/math/big/common.odin @@ -158,13 +158,14 @@ Error :: enum int { Invalid_Pointer = 2, Invalid_Argument = 3, - Assignment_To_Immutable = 4, - Max_Iterations_Reached = 5, - Buffer_Overflow = 6, - Integer_Overflow = 7, + Assignment_To_Immutable = 10, + Max_Iterations_Reached = 11, + Buffer_Overflow = 12, + Integer_Overflow = 13, + Integer_Underflow = 14, - Division_by_Zero = 8, - Math_Domain_Error = 9, + Division_by_Zero = 30, + Math_Domain_Error = 31, Cannot_Open_File = 50, Cannot_Read_File = 51, @@ -215,7 +216,7 @@ _MIN_DIGIT_COUNT :: max(3, ((size_of(u128) + _DIGIT_BITS) - 1) / _DIGIT_BITS) /* Maximum number of digits. - Must be small enough such that `_bit_count` does not overflow. - - Must be small enough such that `_radix_size` for base 2 does not overflow. + - Must be small enough such that `_radix_size` for base 2 does not overflow. `_radix_size` needs two additional bytes for zero termination and sign. */ _MAX_BIT_COUNT :: (max(int) - 2) @@ -251,7 +252,7 @@ Order :: enum i8 { } Endianness :: enum i8 { - Little = -1, - Platform = 0, - Big = 1, -};
\ No newline at end of file + Little = -1, + Platform = 0, + Big = 1, +}
\ No newline at end of file diff --git a/core/math/big/internal.odin b/core/math/big/internal.odin index 4702e76a3..437f6e5fc 100644 --- a/core/math/big/internal.odin +++ b/core/math/big/internal.odin @@ -34,6 +34,7 @@ package math_big import "core:mem" import "core:intrinsics" import rnd "core:math/rand" +import "core:builtin" /* Low-level addition, unsigned. Handbook of Applied Cryptography, algorithm 14.7. @@ -1880,8 +1881,6 @@ internal_int_set_from_integer :: proc(dest: ^Int, src: $T, minimize := false, al where intrinsics.type_is_integer(T) { context.allocator = allocator - src := src - internal_error_if_immutable(dest) or_return /* Most internal procs asssume an Int to have already been initialize, @@ -1892,13 +1891,27 @@ internal_int_set_from_integer :: proc(dest: ^Int, src: $T, minimize := false, al dest.flags = {} // We're not -Inf, Inf, NaN or Immutable. dest.used = 0 - dest.sign = .Zero_or_Positive if src >= 0 else .Negative - src = internal_abs(src) + dest.sign = .Negative if src < 0 else .Zero_or_Positive + + temp := src + + is_maximally_negative := src == min(T) + if is_maximally_negative { + /* + Prevent overflow on abs() + */ + temp += 1 + } + temp = -temp if temp < 0 else temp - #no_bounds_check for src != 0 { - dest.digit[dest.used] = DIGIT(src) & _MASK + #no_bounds_check for temp != 0 { + dest.digit[dest.used] = DIGIT(temp) & _MASK dest.used += 1 - src >>= _DIGIT_BITS + temp >>= _DIGIT_BITS + } + + if is_maximally_negative { + return internal_sub(dest, dest, 1) } internal_zero_unused(dest) return nil @@ -2307,29 +2320,70 @@ internal_int_get_i32 :: proc(a: ^Int) -> (res: i32, err: Error) { } internal_get_i32 :: proc { internal_int_get_i32, } +internal_get_low_u32 :: proc(a: ^Int) -> u32 #no_bounds_check { + if a == nil { + return 0 + } + + if a.used == 0 { + return 0 + } + + return u32(a.digit[0]) +} +internal_get_low_u64 :: proc(a: ^Int) -> u64 #no_bounds_check { + if a == nil { + return 0 + } + + if a.used == 0 { + return 0 + } + + v := u64(a.digit[0]) + when size_of(DIGIT) == 4 { + if a.used > 1 { + return u64(a.digit[1])<<32 | v + } + } + return v +} + /* TODO: Think about using `count_bits` to check if the value could be returned completely, and maybe return max(T), .Integer_Overflow if not? */ internal_int_get :: proc(a: ^Int, $T: typeid) -> (res: T, err: Error) where intrinsics.type_is_integer(T) { - size_in_bits := int(size_of(T) * 8) - i := int((size_in_bits + _DIGIT_BITS - 1) / _DIGIT_BITS) - i = min(int(a.used), i) - - #no_bounds_check for ; i >= 0; i -= 1 { - res <<= uint(0) if size_in_bits <= _DIGIT_BITS else _DIGIT_BITS - res |= T(a.digit[i]) - if size_in_bits <= _DIGIT_BITS { - break + /* + Calculate target bit size. + */ + target_bit_size := int(size_of(T) * 8) + when !intrinsics.type_is_unsigned(T) { + if a.sign == .Zero_or_Positive { + target_bit_size -= 1 + } + } else { + if a.sign == .Negative { + return 0, .Integer_Underflow + } + } + + bits_used := internal_count_bits(a) + + if bits_used > target_bit_size { + if a.sign == .Negative { + return min(T), .Integer_Underflow } + return max(T), .Integer_Overflow + } + + for i := a.used; i > 0; i -= 1 { + res <<= _DIGIT_BITS + res |= T(a.digit[i - 1]) } when !intrinsics.type_is_unsigned(T) { /* - Mask off sign bit. - */ - res ~= 1 << uint(size_in_bits - 1) - /* Set the sign. */ if a.sign == .Negative { res = -res } @@ -2594,7 +2648,7 @@ internal_int_shrmod :: proc(quotient, remainder, numerator: ^Int, bits: int, all Shift by as many digits in the bit count. */ if bits >= _DIGIT_BITS { - internal_shr_digit(quotient, bits / _DIGIT_BITS) or_return + _private_int_shr_leg(quotient, bits / _DIGIT_BITS) or_return } /* @@ -2634,37 +2688,6 @@ internal_int_shr :: proc(dest, source: ^Int, bits: int, allocator := context.all internal_shr :: proc { internal_int_shr, } /* - Shift right by `digits` * _DIGIT_BITS bits. -*/ -internal_int_shr_digit :: proc(quotient: ^Int, digits: int, allocator := context.allocator) -> (err: Error) { - context.allocator = allocator - - if digits <= 0 { return nil } - - /* - If digits > used simply zero and return. - */ - if digits > quotient.used { return internal_zero(quotient) } - - /* - Much like `int_shl_digit`, this is implemented using a sliding window, - except the window goes the other way around. - - b-2 | b-1 | b0 | b1 | b2 | ... | bb | ----> - /\ | ----> - \-------------------/ ----> - */ - - #no_bounds_check for x := 0; x < (quotient.used - digits); x += 1 { - quotient.digit[x] = quotient.digit[x + digits] - } - quotient.used -= digits - internal_zero_unused(quotient) - return internal_clamp(quotient) -} -internal_shr_digit :: proc { internal_int_shr_digit, } - -/* Shift right by a certain bit count with sign extension. */ internal_int_shr_signed :: proc(dest, src: ^Int, bits: int, allocator := context.allocator) -> (err: Error) { @@ -2702,7 +2725,7 @@ internal_int_shl :: proc(dest, src: ^Int, bits: int, allocator := context.alloca Shift by as many digits in the bit count as we have. */ if bits >= _DIGIT_BITS { - internal_shl_digit(dest, bits / _DIGIT_BITS) or_return + _private_int_shl_leg(dest, bits / _DIGIT_BITS) or_return } /* @@ -2732,45 +2755,6 @@ internal_int_shl :: proc(dest, src: ^Int, bits: int, allocator := context.alloca } internal_shl :: proc { internal_int_shl, } - -/* - Shift left by `digits` * _DIGIT_BITS bits. -*/ -internal_int_shl_digit :: proc(quotient: ^Int, digits: int, allocator := context.allocator) -> (err: Error) { - context.allocator = allocator - - if digits <= 0 { return nil } - - /* - No need to shift a zero. - */ - if #force_inline internal_is_zero(quotient) { - return nil - } - - /* - Resize `quotient` to accomodate extra digits. - */ - #force_inline internal_grow(quotient, quotient.used + digits) or_return - - /* - Increment the used by the shift amount then copy upwards. - */ - - /* - Much like `int_shr_digit`, this is implemented using a sliding window, - except the window goes the other way around. - */ - #no_bounds_check for x := quotient.used; x > 0; x -= 1 { - quotient.digit[x+digits-1] = quotient.digit[x-1] - } - - quotient.used += digits - mem.zero_slice(quotient.digit[:digits]) - return nil -} -internal_shl_digit :: proc { internal_int_shl_digit, } - /* Count bits in an `Int`. Assumes `a` not to be `nil` and to have been initialized. diff --git a/core/math/big/logical.odin b/core/math/big/logical.odin index dbcf566c8..e7e55cc47 100644 --- a/core/math/big/logical.odin +++ b/core/math/big/logical.odin @@ -87,21 +87,6 @@ int_shr :: proc(dest, source: ^Int, bits: int, allocator := context.allocator) - shr :: proc { int_shr, } /* - Shift right by `digits` * _DIGIT_BITS bits. -*/ -int_shr_digit :: proc(quotient: ^Int, digits: int, allocator := context.allocator) -> (err: Error) { - /* - Check that `quotient` is usable. - */ - assert_if_nil(quotient) - context.allocator = allocator - - internal_clear_if_uninitialized(quotient) or_return - return #force_inline internal_int_shr_digit(quotient, digits) -} -shr_digit :: proc { int_shr_digit, } - -/* Shift right by a certain bit count with sign extension. */ int_shr_signed :: proc(dest, src: ^Int, bits: int, allocator := context.allocator) -> (err: Error) { @@ -124,20 +109,4 @@ int_shl :: proc(dest, src: ^Int, bits: int, allocator := context.allocator) -> ( internal_clear_if_uninitialized(dest, src) or_return return #force_inline internal_int_shl(dest, src, bits) } -shl :: proc { int_shl, } - - -/* - Shift left by `digits` * _DIGIT_BITS bits. -*/ -int_shl_digit :: proc(quotient: ^Int, digits: int, allocator := context.allocator) -> (err: Error) { - /* - Check that `quotient` is usable. - */ - assert_if_nil(quotient) - context.allocator = allocator - - internal_clear_if_uninitialized(quotient) or_return - return #force_inline internal_int_shl_digit(quotient, digits) -} -shl_digit :: proc { int_shl_digit, };
\ No newline at end of file +shl :: proc { int_shl, }
\ No newline at end of file diff --git a/core/math/big/private.odin b/core/math/big/private.odin index 14a27f600..9989a208a 100644 --- a/core/math/big/private.odin +++ b/core/math/big/private.odin @@ -211,12 +211,12 @@ _private_int_mul_toom :: proc(dest, a, b: ^Int, allocator := context.allocator) /*
P = b1*x^4+ S2*x^3+ S1*x^2+ a1*x + a0;
*/
- internal_shl_digit(b1, 4 * B) or_return
- internal_shl_digit(S2, 3 * B) or_return
+ _private_int_shl_leg(b1, 4 * B) or_return
+ _private_int_shl_leg(S2, 3 * B) or_return
internal_add(b1, b1, S2) or_return
- internal_shl_digit(S1, 2 * B) or_return
+ _private_int_shl_leg(S1, 2 * B) or_return
internal_add(b1, b1, S1) or_return
- internal_shl_digit(a1, 1 * B) or_return
+ _private_int_shl_leg(a1, 1 * B) or_return
internal_add(b1, b1, a1) or_return
internal_add(dest, b1, a0) or_return
@@ -317,8 +317,8 @@ _private_int_mul_karatsuba :: proc(dest, a, b: ^Int, allocator := context.alloca /*
shift by B.
*/
- internal_shl_digit(t1, B) or_return /* t1 = (x0y0 + x1y1 - (x1-x0)*(y1-y0))<<B */
- internal_shl_digit(x1y1, B * 2) or_return /* x1y1 = x1y1 << 2*B */
+ _private_int_shl_leg(t1, B) or_return /* t1 = (x0y0 + x1y1 - (x1-x0)*(y1-y0))<<B */
+ _private_int_shl_leg(x1y1, B * 2) or_return /* x1y1 = x1y1 << 2*B */
internal_add(t1, x0y0, t1) or_return /* t1 = x0y0 + t1 */
internal_add(dest, t1, x1y1) or_return /* t1 = x0y0 + t1 + x1y1 */
@@ -588,7 +588,7 @@ _private_int_mul_balance :: proc(dest, a, b: ^Int, allocator := context.allocato /*
Shift `tmp` to the correct position.
*/
- internal_shl_digit(tmp, b_size * i) or_return
+ _private_int_shl_leg(tmp, b_size * i) or_return
/*
Add to output. No carry needed.
@@ -606,7 +606,7 @@ _private_int_mul_balance :: proc(dest, a, b: ^Int, allocator := context.allocato internal_clamp(a0)
internal_mul(tmp, a0, b) or_return
- internal_shl_digit(tmp, b_size * i) or_return
+ _private_int_shl_leg(tmp, b_size * i) or_return
internal_add(r, r, tmp) or_return
}
@@ -840,8 +840,8 @@ _private_int_sqr_karatsuba :: proc(dest, src: ^Int, allocator := context.allocat /*
Shift by B.
*/
- internal_shl_digit(t1, B) or_return
- internal_shl_digit(x1x1, B * 2) or_return
+ _private_int_shl_leg(t1, B) or_return
+ _private_int_shl_leg(x1x1, B * 2) or_return
internal_add(t1, t1, x0x0) or_return
internal_add(dest, t1, x1x1) or_return
@@ -942,10 +942,10 @@ _private_int_sqr_toom :: proc(dest, src: ^Int, allocator := context.allocator) - internal_sub(dest, dest, S0) or_return
/** \\P = S4*x^4 + S3*x^3 + S2*x^2 + S1*x + S0; */
/** P = a2*x^4 + a1*x^3 + b*x^2 + a0*x + S0; */
- internal_shl_digit( a2, 4 * B) or_return
- internal_shl_digit( a1, 3 * B) or_return
- internal_shl_digit(dest, 2 * B) or_return
- internal_shl_digit( a0, 1 * B) or_return
+ _private_int_shl_leg( a2, 4 * B) or_return
+ _private_int_shl_leg( a1, 3 * B) or_return
+ _private_int_shl_leg(dest, 2 * B) or_return
+ _private_int_shl_leg( a0, 1 * B) or_return
internal_add(a2, a2, a1) or_return
internal_add(dest, dest, a2) or_return
@@ -1069,7 +1069,7 @@ _private_int_div_school :: proc(quotient, remainder, numerator, denominator: ^In y = y*b**{n-t}
*/
- internal_shl_digit(y, n - t) or_return
+ _private_int_shl_leg(y, n - t) or_return
gte := internal_gte(x, y)
for gte {
@@ -1081,7 +1081,7 @@ _private_int_div_school :: proc(quotient, remainder, numerator, denominator: ^In /*
Reset y by shifting it back down.
*/
- internal_shr_digit(y, n - t)
+ _private_int_shr_leg(y, n - t)
/*
Step 3. for i from n down to (t + 1).
@@ -1146,7 +1146,7 @@ _private_int_div_school :: proc(quotient, remainder, numerator, denominator: ^In Step 3.3 x = x - q{i-t-1} * y * b**{i-t-1}
*/
int_mul_digit(t1, y, q.digit[(i - t) - 1]) or_return
- internal_shl_digit(t1, (i - t) - 1) or_return
+ _private_int_shl_leg(t1, (i - t) - 1) or_return
internal_sub(x, x, t1) or_return
/*
@@ -1154,7 +1154,7 @@ _private_int_div_school :: proc(quotient, remainder, numerator, denominator: ^In */
if x.sign == .Negative {
internal_copy(t1, y) or_return
- internal_shl_digit(t1, (i - t) - 1) or_return
+ _private_int_shl_leg(t1, (i - t) - 1) or_return
internal_add(x, x, t1) or_return
q.digit[(i - t) - 1] = (q.digit[(i - t) - 1] - 1) & _MASK
@@ -1220,7 +1220,7 @@ _private_div_recursion :: proc(quotient, remainder, a, b: ^Int, allocator := con /*
A1 = (R1 * beta^(2k)) + (A % beta^(2k)) - (Q1 * B0 * beta^k)
*/
- internal_shl_digit(R1, 2 * k) or_return
+ _private_int_shl_leg(R1, 2 * k) or_return
internal_add(A1, R1, t) or_return
internal_mul(t, Q1, B0) or_return
@@ -1246,7 +1246,7 @@ _private_div_recursion :: proc(quotient, remainder, a, b: ^Int, allocator := con /*
A2 = (R0*beta^k) + (A1 % beta^k) - (Q0*B0)
*/
- internal_shl_digit(R0, k) or_return
+ _private_int_shl_leg(R0, k) or_return
internal_add(A2, R0, t) or_return
internal_mul(t, Q0, B0) or_return
internal_sub(A2, A2, t) or_return
@@ -1262,7 +1262,7 @@ _private_div_recursion :: proc(quotient, remainder, a, b: ^Int, allocator := con /*
Return q = (Q1*beta^k) + Q0, r = A2.
*/
- internal_shl_digit(Q1, k) or_return
+ _private_int_shl_leg(Q1, k) or_return
internal_add(quotient, Q1, Q0) or_return
return internal_copy(remainder, A2)
@@ -1923,7 +1923,7 @@ _private_int_montgomery_reduce :: proc(x, n: ^Int, rho: DIGIT, allocator := cont x = x/b**n.used.
*/
internal_clamp(x)
- internal_shr_digit(x, n.used)
+ _private_int_shr_leg(x, n.used)
/*
if x >= n then x = x - n
@@ -2026,7 +2026,7 @@ _private_int_reduce :: proc(x, m, mu: ^Int, allocator := context.allocator) -> ( /*
q1 = x / b**(k-1)
*/
- internal_shr_digit(q, um - 1)
+ _private_int_shr_leg(q, um - 1)
/*
According to HAC this optimization is ok.
@@ -2040,7 +2040,7 @@ _private_int_reduce :: proc(x, m, mu: ^Int, allocator := context.allocator) -> ( /*
q3 = q2 / b**(k+1)
*/
- internal_shr_digit(q, um + 1)
+ _private_int_shr_leg(q, um + 1)
/*
x = x mod b**(k+1), quick (no division)
@@ -2062,7 +2062,7 @@ _private_int_reduce :: proc(x, m, mu: ^Int, allocator := context.allocator) -> ( */
if internal_is_negative(x) {
internal_set(q, 1) or_return
- internal_shl_digit(q, um + 1) or_return
+ _private_int_shl_leg(q, um + 1) or_return
internal_add(x, x, q) or_return
}
@@ -3192,6 +3192,74 @@ _private_copy_digits :: proc(dest, src: ^Int, digits: int, offset := int(0)) -> return nil
}
+
+/*
+ Shift left by `digits` * _DIGIT_BITS bits.
+*/
+_private_int_shl_leg :: proc(quotient: ^Int, digits: int, allocator := context.allocator) -> (err: Error) {
+ context.allocator = allocator
+
+ if digits <= 0 { return nil }
+
+ /*
+ No need to shift a zero.
+ */
+ if #force_inline internal_is_zero(quotient) {
+ return nil
+ }
+
+ /*
+ Resize `quotient` to accomodate extra digits.
+ */
+ #force_inline internal_grow(quotient, quotient.used + digits) or_return
+
+ /*
+ Increment the used by the shift amount then copy upwards.
+ */
+
+ /*
+ Much like `_private_int_shr_leg`, this is implemented using a sliding window,
+ except the window goes the other way around.
+ */
+ #no_bounds_check for x := quotient.used; x > 0; x -= 1 {
+ quotient.digit[x+digits-1] = quotient.digit[x-1]
+ }
+
+ quotient.used += digits
+ mem.zero_slice(quotient.digit[:digits])
+ return nil
+}
+
+/*
+ Shift right by `digits` * _DIGIT_BITS bits.
+*/
+_private_int_shr_leg :: proc(quotient: ^Int, digits: int, allocator := context.allocator) -> (err: Error) {
+ context.allocator = allocator
+
+ if digits <= 0 { return nil }
+
+ /*
+ If digits > used simply zero and return.
+ */
+ if digits > quotient.used { return internal_zero(quotient) }
+
+ /*
+ Much like `int_shl_digit`, this is implemented using a sliding window,
+ except the window goes the other way around.
+
+ b-2 | b-1 | b0 | b1 | b2 | ... | bb | ---->
+ /\ | ---->
+ \-------------------/ ---->
+ */
+
+ #no_bounds_check for x := 0; x < (quotient.used - digits); x += 1 {
+ quotient.digit[x] = quotient.digit[x + digits]
+ }
+ quotient.used -= digits
+ internal_zero_unused(quotient)
+ return internal_clamp(quotient)
+}
+
/*
======================== End of private procedures =======================
diff --git a/core/math/big/rat.odin b/core/math/big/rat.odin index 837af6fd3..c3efc30aa 100644 --- a/core/math/big/rat.odin +++ b/core/math/big/rat.odin @@ -42,9 +42,9 @@ rat_set_f64 :: proc(dst: ^Rat, f: f64, allocator := context.allocator) -> (err: dst.a.sign = .Negative if f < 0 else .Zero_or_Positive if shift > 0 { - internal_int_shl_digit(&dst.b, shift) or_return + internal_int_shl(&dst.b, &dst.b, shift) or_return } else { - internal_int_shl_digit(&dst.a, -shift) or_return + internal_int_shl(&dst.a, &dst.a, -shift) or_return } return internal_rat_norm(dst) @@ -389,9 +389,9 @@ internal_rat_to_float :: proc($T: typeid, z: ^Rat, allocator := context.allocato 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 + internal_int_shl(a2, a2, shift) or_return + } else if shift < 0 { + internal_int_shl(b2, b2, -shift) or_return } q, r := &Int{}, &Int{} diff --git a/core/math/math.odin b/core/math/math.odin index caaa6f51b..b81598da9 100644 --- a/core/math/math.odin +++ b/core/math/math.odin @@ -1196,6 +1196,7 @@ sum :: proc "contextless" (x: $T/[]$E) -> (res: E) prod :: proc "contextless" (x: $T/[]$E) -> (res: E) where intrinsics.type_is_numeric(E) { + res = 1 for i in x { res *= i } diff --git a/core/runtime/internal.odin b/core/runtime/internal.odin index ed58f4318..6498c4db7 100644 --- a/core/runtime/internal.odin +++ b/core/runtime/internal.odin @@ -2,13 +2,15 @@ package runtime import "core:intrinsics" +@(private="file") +IS_WASM :: ODIN_ARCH == "wasm32" || ODIN_ARCH == "wasm64" + @(private) RUNTIME_LINKAGE :: "strong" when ( (ODIN_USE_SEPARATE_MODULES || ODIN_BUILD_MODE == "dynamic" || !ODIN_NO_CRT) && - !(ODIN_ARCH == "wasm32" || - ODIN_ARCH == "wasm64")) else "internal" + !IS_WASM) else "internal" RUNTIME_REQUIRE :: true @@ -752,6 +754,9 @@ extendhfsf2 :: proc "c" (value: u16) -> f32 { @(link_name="__floattidf", linkage=RUNTIME_LINKAGE, require=RUNTIME_REQUIRE) floattidf :: proc "c" (a: i128) -> f64 { +when IS_WASM { + return 0 +} else { DBL_MANT_DIG :: 53 if a == 0 { return 0.0 @@ -791,10 +796,14 @@ floattidf :: proc "c" (a: i128) -> f64 { fb[0] = u32(a) // mantissa-low return transmute(f64)fb } +} @(link_name="__floattidf_unsigned", linkage=RUNTIME_LINKAGE, require=RUNTIME_REQUIRE) floattidf_unsigned :: proc "c" (a: u128) -> f64 { +when IS_WASM { + return 0 +} else { DBL_MANT_DIG :: 53 if a == 0 { return 0.0 @@ -832,6 +841,7 @@ floattidf_unsigned :: proc "c" (a: u128) -> f64 { fb[0] = u32(a) // mantissa-low return transmute(f64)fb } +} diff --git a/core/runtime/procs_wasm32.odin b/core/runtime/procs_wasm32.odin index 5caf6d2f8..2a4210c1e 100644 --- a/core/runtime/procs_wasm32.odin +++ b/core/runtime/procs_wasm32.odin @@ -1,23 +1,40 @@ //+build wasm32 package runtime +@(private="file") +ti_int :: struct #raw_union { + using s: struct { lo, hi: u64 }, + all: i128, +} + @(link_name="__ashlti3", linkage="strong") -__ashlti3 :: proc "c" (a: i64, b_: i32) -> i64 { - /* +__ashlti3 :: proc "c" (a: i128, b_: u32) -> i128 { + bits_in_dword :: size_of(u32)*8 b := u32(b_) - input := transmute([2]i32)a - result: [2]i32 - if b & 32 != 0 { - result[0] = 0 - result[1] = input[0] << (b - 32) + + input, result: ti_int + input.all = a + if b & bits_in_dword != 0 { + result.lo = 0 + result.hi = input.lo << (b-bits_in_dword) } else { if b == 0 { return a } - result[0] = input[0]<<b - result[1] = (input[1]<<b) | (input[0]>>(32-b)) + result.lo = input.lo<<b + result.hi = (input.hi<<b) | (input.lo>>(bits_in_dword-b)) } - return transmute(i64)result - */ - return 0 + return result.all +} + + +@(link_name="__multi3", linkage="strong") +__multi3 :: proc "c" (a, b: i128) -> i128 { + x, y, r: ti_int + + x.all = a + y.all = b + r.all = i128(x.lo * y.lo) // TODO this is incorrect + r.hi += x.hi*y.lo + x.lo*y.hi + return r.all }
\ No newline at end of file diff --git a/core/strconv/strconv.odin b/core/strconv/strconv.odin index 6b3a91b4c..6ea8b39e6 100644 --- a/core/strconv/strconv.odin +++ b/core/strconv/strconv.odin @@ -882,7 +882,9 @@ unquote_string :: proc(lit: string, allocator := context.allocator) -> (res: str return -1 } - assert(len(lit) >= 2) + if len(lit) < 2 { + return + } if lit[0] == '`' { return lit[1:len(lit)-1], false, true } diff --git a/core/strings/strings.odin b/core/strings/strings.odin index a8199e0cf..3f703372f 100644 --- a/core/strings/strings.odin +++ b/core/strings/strings.odin @@ -504,8 +504,8 @@ index_any :: proc(s, chars: string) -> int { } } - for c in chars { - if i := index_rune(s, c); i >= 0 { + for c, i in s { + if index_rune(chars, c) >= 0 { return i } } @@ -1288,7 +1288,7 @@ fields_proc :: proc(s: string, f: proc(rune) -> bool, allocator := context.alloc } if start >= 0 { - append(&substrings, s[start : end]) + append(&substrings, s[start : len(s)]) } return substrings[:] diff --git a/src/check_stmt.cpp b/src/check_stmt.cpp index 1a424240c..396388629 100644 --- a/src/check_stmt.cpp +++ b/src/check_stmt.cpp @@ -2243,6 +2243,9 @@ void check_stmt_internal(CheckerContext *ctx, Ast *node, u32 flags) { error(e->token, "The 'static' attribute is not allowed to be applied to '_'"); } else { e->flags |= EntityFlag_Static; + if (ctx->in_defer) { + error(e->token, "'static' variables cannot be declared within a defer statement"); + } } } if (ac.thread_local_model != "") { @@ -2251,9 +2254,13 @@ void check_stmt_internal(CheckerContext *ctx, Ast *node, u32 flags) { error(e->token, "The 'thread_local' attribute is not allowed to be applied to '_'"); } else { e->flags |= EntityFlag_Static; + if (ctx->in_defer) { + error(e->token, "'thread_local' variables cannot be declared within a defer statement"); + } } e->Variable.thread_local_model = ac.thread_local_model; } + if (ac.is_static && ac.thread_local_model != "") { error(e->token, "The 'static' attribute is not needed if 'thread_local' is applied"); diff --git a/src/llvm_backend_opt.cpp b/src/llvm_backend_opt.cpp index de925655f..5b8468799 100644 --- a/src/llvm_backend_opt.cpp +++ b/src/llvm_backend_opt.cpp @@ -48,12 +48,6 @@ LLVMBool lb_must_preserve_predicate_callback(LLVMValueRef value, void *user_data return LLVMIsAAllocaInst(value) != nullptr; } -void lb_add_must_preserve_predicate_pass(lbModule *m, LLVMPassManagerRef fpm, i32 optimization_level) { - if (false && optimization_level == 0 && m->debug_builder) { - // LLVMAddInternalizePassWithMustPreservePredicate(fpm, m, lb_must_preserve_predicate_callback); - } -} - #if LLVM_VERSION_MAJOR < 12 #define LLVM_ADD_CONSTANT_VALUE_PASS(fpm) LLVMAddConstantPropagationPass(fpm) @@ -61,7 +55,10 @@ void lb_add_must_preserve_predicate_pass(lbModule *m, LLVMPassManagerRef fpm, i3 #define LLVM_ADD_CONSTANT_VALUE_PASS(fpm) #endif -void lb_basic_populate_function_pass_manager(LLVMPassManagerRef fpm) { +void lb_basic_populate_function_pass_manager(LLVMPassManagerRef fpm, i32 optimization_level) { + if (optimization_level == 0 && build_context.ODIN_DEBUG) { + return; + } LLVMAddPromoteMemoryToRegisterPass(fpm); LLVMAddMergedLoadStoreMotionPass(fpm); LLVM_ADD_CONSTANT_VALUE_PASS(fpm); @@ -78,14 +75,12 @@ void lb_populate_function_pass_manager(lbModule *m, LLVMPassManagerRef fpm, bool // TODO(bill): Determine which opt definitions should exist in the first place optimization_level = gb_clamp(optimization_level, 0, 2); - lb_add_must_preserve_predicate_pass(m, fpm, optimization_level); - if (ignore_memcpy_pass) { - lb_basic_populate_function_pass_manager(fpm); + lb_basic_populate_function_pass_manager(fpm, optimization_level); return; } else if (optimization_level == 0) { LLVMAddMemCpyOptPass(fpm); - lb_basic_populate_function_pass_manager(fpm); + lb_basic_populate_function_pass_manager(fpm, optimization_level); return; } @@ -96,7 +91,7 @@ void lb_populate_function_pass_manager(lbModule *m, LLVMPassManagerRef fpm, bool LLVMPassManagerBuilderPopulateFunctionPassManager(pmb, fpm); #else LLVMAddMemCpyOptPass(fpm); - lb_basic_populate_function_pass_manager(fpm); + lb_basic_populate_function_pass_manager(fpm, optimization_level); LLVMAddSCCPPass(fpm); @@ -114,11 +109,9 @@ void lb_populate_function_pass_manager_specific(lbModule *m, LLVMPassManagerRef // TODO(bill): Determine which opt definitions should exist in the first place optimization_level = gb_clamp(optimization_level, 0, 2); - lb_add_must_preserve_predicate_pass(m, fpm, optimization_level); - if (optimization_level == 0) { LLVMAddMemCpyOptPass(fpm); - lb_basic_populate_function_pass_manager(fpm); + lb_basic_populate_function_pass_manager(fpm, optimization_level); return; } @@ -191,6 +184,9 @@ void lb_populate_module_pass_manager(LLVMTargetMachineRef target_machine, LLVMPa // NOTE(bill): Treat -opt:3 as if it was -opt:2 // TODO(bill): Determine which opt definitions should exist in the first place optimization_level = gb_clamp(optimization_level, 0, 2); + if (optimization_level == 0 && build_context.ODIN_DEBUG) { + return; + } LLVMAddAlwaysInlinerPass(mpm); LLVMAddStripDeadPrototypesPass(mpm); diff --git a/tests/core/math/big/test.odin b/tests/core/math/big/test.odin index 07fa0364b..81f1956dc 100644 --- a/tests/core/math/big/test.odin +++ b/tests/core/math/big/test.odin @@ -208,7 +208,7 @@ print_to_buffer :: proc(val: ^big.Int) -> cstring { /* dest = shr_digit(src, digits) */ -@export test_shr_digit :: proc "c" (source: cstring, digits: int) -> (res: PyRes) { +@export test_shr_leg :: proc "c" (source: cstring, digits: int) -> (res: PyRes) { context = runtime.default_context() err: big.Error @@ -216,7 +216,7 @@ print_to_buffer :: proc(val: ^big.Int) -> cstring { defer big.internal_destroy(src) if err = big.atoi(src, string(source), 16); err != nil { return PyRes{res=":shr_digit:atoi(src):", err=err} } - if err = #force_inline big.internal_shr_digit(src, digits); err != nil { return PyRes{res=":shr_digit:shr_digit(src):", err=err} } + if err = #force_inline big._private_int_shr_leg(src, digits); err != nil { return PyRes{res=":shr_digit:shr_digit(src):", err=err} } r := print_to_buffer(src) return PyRes{res = r, err = nil} @@ -225,7 +225,7 @@ print_to_buffer :: proc(val: ^big.Int) -> cstring { /* dest = shl_digit(src, digits) */ -@export test_shl_digit :: proc "c" (source: cstring, digits: int) -> (res: PyRes) { +@export test_shl_leg :: proc "c" (source: cstring, digits: int) -> (res: PyRes) { context = runtime.default_context() err: big.Error @@ -233,7 +233,7 @@ print_to_buffer :: proc(val: ^big.Int) -> cstring { defer big.internal_destroy(src) if err = big.atoi(src, string(source), 16); err != nil { return PyRes{res=":shl_digit:atoi(src):", err=err} } - if err = #force_inline big.internal_shl_digit(src, digits); err != nil { return PyRes{res=":shl_digit:shr_digit(src):", err=err} } + if err = #force_inline big._private_int_shl_leg(src, digits); err != nil { return PyRes{res=":shl_digit:shr_digit(src):", err=err} } r := print_to_buffer(src) return PyRes{res = r, err = nil} diff --git a/tests/core/math/big/test.py b/tests/core/math/big/test.py index 6b17336bc..d292a3ff4 100644 --- a/tests/core/math/big/test.py +++ b/tests/core/math/big/test.py @@ -127,17 +127,22 @@ def we_iterate(): # Error enum values
#
class Error(Enum):
- Okay = 0
- Out_Of_Memory = 1
- Invalid_Pointer = 2
- Invalid_Argument = 3
- Unknown_Error = 4
- Max_Iterations_Reached = 5
- Buffer_Overflow = 6
- Integer_Overflow = 7
- Division_by_Zero = 8
- Math_Domain_Error = 9
- Unimplemented = 127
+ Okay = 0
+ Out_Of_Memory = 1
+ Invalid_Pointer = 2
+ Invalid_Argument = 3
+ Unknown_Error = 4
+ Assignment_To_Immutable = 10
+ Max_Iterations_Reached = 11
+ Buffer_Overflow = 12
+ Integer_Overflow = 13
+ Integer_Underflow = 14
+ Division_by_Zero = 30
+ Math_Domain_Error = 31
+ Cannot_Open_File = 50
+ Cannot_Read_File = 51
+ Cannot_Write_File = 52
+ Unimplemented = 127
#
# Disable garbage collection
@@ -182,8 +187,8 @@ int_sqrt = load(l.test_sqrt, [c_char_p ], Res) int_root_n = load(l.test_root_n, [c_char_p, c_longlong], Res)
# Logical operations
-int_shl_digit = load(l.test_shl_digit, [c_char_p, c_longlong], Res)
-int_shr_digit = load(l.test_shr_digit, [c_char_p, c_longlong], Res)
+int_shl_leg = load(l.test_shl_leg, [c_char_p, c_longlong], Res)
+int_shr_leg = load(l.test_shr_leg, [c_char_p, c_longlong], Res)
int_shl = load(l.test_shl, [c_char_p, c_longlong], Res)
int_shr = load(l.test_shr, [c_char_p, c_longlong], Res)
int_shr_signed = load(l.test_shr_signed, [c_char_p, c_longlong], Res)
@@ -397,17 +402,17 @@ def test_root_n(number = 0, root = 0, expected_error = Error.Okay): return test("test_root_n", res, [number, root], expected_error, expected_result)
-def test_shl_digit(a = 0, digits = 0, expected_error = Error.Okay):
+def test_shl_leg(a = 0, digits = 0, expected_error = Error.Okay):
args = [arg_to_odin(a), digits]
- res = int_shl_digit(*args)
+ res = int_shl_leg(*args)
expected_result = None
if expected_error == Error.Okay:
expected_result = a << (digits * 60)
- return test("test_shl_digit", res, [a, digits], expected_error, expected_result)
+ return test("test_shl_leg", res, [a, digits], expected_error, expected_result)
-def test_shr_digit(a = 0, digits = 0, expected_error = Error.Okay):
+def test_shr_leg(a = 0, digits = 0, expected_error = Error.Okay):
args = [arg_to_odin(a), digits]
- res = int_shr_digit(*args)
+ res = int_shr_leg(*args)
expected_result = None
if expected_error == Error.Okay:
if a < 0:
@@ -416,7 +421,7 @@ def test_shr_digit(a = 0, digits = 0, expected_error = Error.Okay): else:
expected_result = a >> (digits * 60)
- return test("test_shr_digit", res, [a, digits], expected_error, expected_result)
+ return test("test_shr_leg", res, [a, digits], expected_error, expected_result)
def test_shl(a = 0, bits = 0, expected_error = Error.Okay):
args = [arg_to_odin(a), bits]
@@ -551,12 +556,12 @@ TESTS = { test_root_n: [
[ 1298074214633706907132624082305024, 2, Error.Okay, ],
],
- test_shl_digit: [
+ test_shl_leg: [
[ 3192, 1 ],
[ 1298074214633706907132624082305024, 2 ],
[ 1024, 3 ],
],
- test_shr_digit: [
+ test_shr_leg: [
[ 3680125442705055547392, 1 ],
[ 1725436586697640946858688965569256363112777243042596638790631055949824, 2 ],
[ 219504133884436710204395031992179571, 2 ],
@@ -614,10 +619,10 @@ total_failures = 0 # test_shr_signed also tests shr, so we're not going to test shr randomly.
#
RANDOM_TESTS = [
- test_add, test_sub, test_mul, test_sqr, test_div,
- test_log, test_pow, test_sqrt, test_root_n,
- test_shl_digit, test_shr_digit, test_shl, test_shr_signed,
- test_gcd, test_lcm, test_is_square,
+ test_add, test_sub, test_mul, test_sqr,
+ test_log, test_pow, test_sqrt, test_root_n,
+ test_shl_leg, test_shr_leg, test_shl, test_shr_signed,
+ test_gcd, test_lcm, test_is_square, test_div,
]
SKIP_LARGE = [
test_pow, test_root_n, # test_gcd,
@@ -714,9 +719,9 @@ if __name__ == '__main__': a = randint(1, 1 << BITS)
b = TEST_ROOT_N_PARAMS[index]
index = (index + 1) % len(TEST_ROOT_N_PARAMS)
- elif test_proc == test_shl_digit:
+ elif test_proc == test_shl_leg:
b = randint(0, 10);
- elif test_proc == test_shr_digit:
+ elif test_proc == test_shr_leg:
a = abs(a)
b = randint(0, 10);
elif test_proc == test_shl:
diff --git a/vendor/wasm/WebGL/runtime.js b/vendor/wasm/WebGL/runtime.js index b6994a8ec..18b540b5c 100644 --- a/vendor/wasm/WebGL/runtime.js +++ b/vendor/wasm/WebGL/runtime.js @@ -416,7 +416,7 @@ class WebGLInterface { log = log.substring(0, n); this.mem.loadBytes(buf_ptr, buf_len).set(new TextEncoder("utf-8").encode(log)) - storeInt(length_ptr, n); + this.mem.storeInt(length_ptr, n); } }, GetShaderInfoLog: (shader, buf_ptr, buf_len, length_ptr) => { @@ -429,7 +429,7 @@ class WebGLInterface { log = log.substring(0, n); this.mem.loadBytes(buf_ptr, buf_len).set(new TextEncoder("utf-8").encode(log)) - storeInt(length_ptr, n); + this.mem.storeInt(length_ptr, n); } }, GetShaderiv: (shader, pname, p) => { @@ -439,11 +439,11 @@ class WebGLInterface { if (log === null) { log = "(unknown error)"; } - storeInt(p, log.length+1); + this.mem.storeInt(p, log.length+1); } else if (pname == 35720) { let source = this.ctx.getShaderSource(this.shaders[shader]); let sourceLength = (source === null || source.length == 0) ? 0 : source.length+1; - storeInt(p, sourceLength); + this.mem.storeInt(p, sourceLength); } else { let param = this.ctx.getShaderParameter(this.shaders[shader], pname); this.mem.storeI32(p, param); @@ -994,7 +994,7 @@ class WebGLInterface { let n = Math.min(buf_len, name.length); name = name.substring(0, n); this.mem.loadBytes(buf_ptr, buf_len).set(new TextEncoder("utf-8").encode(name)) - storeInt(length_ptr, n); + this.mem.storeInt(length_ptr, n); }, UniformBlockBinding: (program, uniformBlockIndex, uniformBlockBinding) => { this.assertWebGL2(); |