Browse Source

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

gingerBill 3 years ago
parent
commit
94bad4d786

+ 8 - 7
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,
-
-	Division_by_Zero        = 8,
-	Math_Domain_Error       = 9,
+	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,

+ 40 - 20
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
@@ -2341,23 +2354,30 @@ internal_get_low_u64 :: proc(a: ^Int) -> u64 #no_bounds_check {
 	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
+		}
+	}
+	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.
 		*/

+ 12 - 2
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
 }
+}
 
 
 

+ 29 - 12
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
 }

+ 16 - 11
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