diff --git a/spec/primitives/int_spec.cr b/spec/primitives/int_spec.cr index 55368eaec91c..603dc4f51b72 100644 --- a/spec/primitives/int_spec.cr +++ b/spec/primitives/int_spec.cr @@ -132,11 +132,9 @@ describe "Primitives: Int" do end describe "#to_f" do - {% if BUILTIN_INTEGER_TYPES.includes?(UInt128) %} - it "raises on overflow for UInt128#to_f32" do - expect_raises(OverflowError) { UInt128::MAX.to_f32 } - expect_raises(OverflowError) { (UInt128::MAX // 2).to_f32 } - end - {% end %} + it "raises on overflow for UInt128#to_f32" do + expect_raises(OverflowError) { UInt128::MAX.to_f32 } + expect_raises(OverflowError) { Float32::MAX.to_u128.succ.to_f32 } # Float32::MAX == 2 ** 128 - 2 ** 104 + end end end diff --git a/spec/std/crystal/hasher_spec.cr b/spec/std/crystal/hasher_spec.cr index f5ae72aadc1b..e75ad3ea9ec5 100644 --- a/spec/std/crystal/hasher_spec.cr +++ b/spec/std/crystal/hasher_spec.cr @@ -57,9 +57,8 @@ describe "Crystal::Hasher" do Int64::MAX.hash.should eq(Int64::MAX.hash) end - # TODO: remove fencing when 128bits support is added to non-native platforms {% if flag?(:bits64) %} - pending_win32 "128bit types should be hashed ok" do + it "128bit types should be hashed ok" do 1.to_i128.hash.should eq(1_i8.hash) 1.to_u128.hash.should eq(1_u8.hash) end diff --git a/spec/std/int_spec.cr b/spec/std/int_spec.cr index 0ebfaaa28261..3263397e2f3a 100644 --- a/spec/std/int_spec.cr +++ b/spec/std/int_spec.cr @@ -188,11 +188,9 @@ describe "Int" do it_converts_to_s 18446744073709551615_u64, "18446744073709551615" - {% unless flag?(:win32) %} - it_converts_to_s UInt128::MAX, "340282366920938463463374607431768211455" - it_converts_to_s Int128::MAX, "170141183460469231731687303715884105727" - it_converts_to_s Int128::MIN, "-170141183460469231731687303715884105728" - {% end %} + it_converts_to_s UInt128::MAX, "340282366920938463463374607431768211455" + it_converts_to_s Int128::MAX, "170141183460469231731687303715884105727" + it_converts_to_s Int128::MIN, "-170141183460469231731687303715884105728" end context "base and upcase parameters" do @@ -515,28 +513,15 @@ describe "Int" do (Int16::MIN / -1).should eq(-(Int16::MIN.to_f64)) (Int32::MIN / -1).should eq(-(Int32::MIN.to_f64)) (Int64::MIN / -1).should eq(-(Int64::MIN.to_f64)) + (Int128::MIN / -1).should eq(-(Int128::MIN.to_f64)) (UInt8::MIN / -1).should eq(0) end - - pending_win32 "divides Int128::MIN by -1" do - (Int128::MIN / -1).should eq(-(Int128::MIN.to_f64)) - end end describe "floor division //" do it "preserves type of lhs" do - {% for type in [UInt8, UInt16, UInt32, UInt64, Int8, Int16, Int32, Int64] %} - ({{type}}.new(7) // 2).should be_a({{type}}) - ({{type}}.new(7) // 2.0).should be_a({{type}}) - ({{type}}.new(7) // 2.0_f32).should be_a({{type}}) - {% end %} - end - - # Missing symbols: __floattidf, __floatuntidf, __fixdfti, __fixsfti, __fixunsdfti, __fixunssfti, __floatuntisf, __floattisf - # These symbols are all required to convert U/Int128s to Floats - pending_win32 "preserves type of lhs (128-bit)" do - {% for type in [UInt128, Int128] %} + {% for type in [UInt8, UInt16, UInt32, UInt64, Int8, Int16, Int32, Int64, UInt128, Int128] %} ({{type}}.new(7) // 2).should be_a({{type}}) ({{type}}.new(7) // 2.0).should be_a({{type}}) ({{type}}.new(7) // 2.0_f32).should be_a({{type}}) @@ -785,13 +770,13 @@ describe "Int" do it "compares signed vs. unsigned integers" do {% begin %} signed_ints = [ - Int8::MAX, Int16::MAX, Int32::MAX, Int64::MAX, {% unless flag?(:win32) %} Int128::MAX, {% end %} - Int8::MIN, Int16::MIN, Int32::MIN, Int64::MIN, {% unless flag?(:win32) %} Int128::MIN, {% end %} - Int8.zero, Int16.zero, Int32.zero, Int64.zero, {% unless flag?(:win32) %} Int128.zero, {% end %} + Int8::MAX, Int16::MAX, Int32::MAX, Int64::MAX, Int128::MAX, + Int8::MIN, Int16::MIN, Int32::MIN, Int64::MIN, Int128::MIN, + Int8.zero, Int16.zero, Int32.zero, Int64.zero, Int128.zero, ] unsigned_ints = [ - UInt8::MAX, UInt16::MAX, UInt32::MAX, UInt64::MAX, {% unless flag?(:win32) %} UInt128::MAX, {% end %} - UInt8.zero, UInt16.zero, UInt32.zero, UInt64.zero, {% unless flag?(:win32) %} UInt128.zero, {% end %} + UInt8::MAX, UInt16::MAX, UInt32::MAX, UInt64::MAX, UInt128::MAX, + UInt8.zero, UInt16.zero, UInt32.zero, UInt64.zero, UInt128.zero, ] big_signed_ints = signed_ints.map &.to_big_i @@ -878,10 +863,6 @@ describe "Int" do Int32::MAX.digits.should eq(Int32::MAX.to_s.chars.map(&.to_i).reverse) Int64::MAX.digits.should eq(Int64::MAX.to_s.chars.map(&.to_i).reverse) UInt64::MAX.digits.should eq(UInt64::MAX.to_s.chars.map(&.to_i).reverse) - end - - # Missing symbol __floatuntidf on windows - pending_win32 "works for u/int128 maximums" do Int128::MAX.digits.should eq(Int128::MAX.to_s.chars.map(&.to_i).reverse) UInt128::MAX.digits.should eq(UInt128::MAX.to_s.chars.map(&.to_i).reverse) end diff --git a/spec/std/string_spec.cr b/spec/std/string_spec.cr index e37646a69150..b9ce2a0d658c 100644 --- a/spec/std/string_spec.cr +++ b/spec/std/string_spec.cr @@ -398,27 +398,27 @@ describe "String" do end describe "to_i128" do - pending_win32 { "170141183460469231731687303715884105727".to_i128.should eq(Int128::MAX) } - pending_win32 { "-170141183460469231731687303715884105728".to_i128.should eq(Int128::MIN) } - pending_win32 { expect_raises(ArgumentError) { "170141183460469231731687303715884105728".to_i128 } } - pending_win32 { expect_raises(ArgumentError) { "-170141183460469231731687303715884105729".to_i128 } } + it { "170141183460469231731687303715884105727".to_i128.should eq(Int128::MAX) } + it { "-170141183460469231731687303715884105728".to_i128.should eq(Int128::MIN) } + it { expect_raises(ArgumentError) { "170141183460469231731687303715884105728".to_i128 } } + it { expect_raises(ArgumentError) { "-170141183460469231731687303715884105729".to_i128 } } - pending_win32 { "170141183460469231731687303715884105727".to_i128?.should eq(Int128::MAX) } - pending_win32 { "170141183460469231731687303715884105728".to_i128?.should be_nil } - pending_win32 { "170141183460469231731687303715884105728".to_i128 { 0 }.should eq(0) } + it { "170141183460469231731687303715884105727".to_i128?.should eq(Int128::MAX) } + it { "170141183460469231731687303715884105728".to_i128?.should be_nil } + it { "170141183460469231731687303715884105728".to_i128 { 0 }.should eq(0) } - pending_win32 { expect_raises(ArgumentError) { "340282366920938463463374607431768211456".to_i128 } } + it { expect_raises(ArgumentError) { "340282366920938463463374607431768211456".to_i128 } } end describe "to_u128" do - pending_win32 { "340282366920938463463374607431768211455".to_u128.should eq(UInt128::MAX) } - pending_win32 { "0".to_u128.should eq(0) } - pending_win32 { expect_raises(ArgumentError) { "340282366920938463463374607431768211456".to_u128 } } - pending_win32 { expect_raises(ArgumentError) { "-1".to_u128 } } - - pending_win32 { "340282366920938463463374607431768211455".to_u128?.should eq(UInt128::MAX) } - pending_win32 { "340282366920938463463374607431768211456".to_u128?.should be_nil } - pending_win32 { "340282366920938463463374607431768211456".to_u128 { 0 }.should eq(0) } + it { "340282366920938463463374607431768211455".to_u128.should eq(UInt128::MAX) } + it { "0".to_u128.should eq(0) } + it { expect_raises(ArgumentError) { "340282366920938463463374607431768211456".to_u128 } } + it { expect_raises(ArgumentError) { "-1".to_u128 } } + + it { "340282366920938463463374607431768211455".to_u128?.should eq(UInt128::MAX) } + it { "340282366920938463463374607431768211456".to_u128?.should be_nil } + it { "340282366920938463463374607431768211456".to_u128 { 0 }.should eq(0) } end it { "1234".to_i32.should eq(1234) } diff --git a/spec/support/number.cr b/spec/support/number.cr index 43a042d688a0..2dfd2493d507 100644 --- a/spec/support/number.cr +++ b/spec/support/number.cr @@ -1,32 +1,17 @@ require "spec/helpers/iterate" # Helper methods to describe the behavior of numbers of different types -# Int128 and UInt128 are excluded from win32 because of incorrect codegen for primitives -{% unless flag?(:win32) %} - BUILTIN_NUMBER_TYPES = - [Int8, UInt8, Int16, UInt16, Int32, UInt32, Int64, UInt64, Int128, UInt128, Float32, Float64] - BUILTIN_INTEGER_TYPES = - [Int8, UInt8, Int16, UInt16, Int32, UInt32, Int64, UInt64, Int128, UInt128] - BUILTIN_INTEGER_TYPES_128 = - [Int128, UInt128] -{% else %} - BUILTIN_NUMBER_TYPES = - [Int8, UInt8, Int16, UInt16, Int32, UInt32, Int64, UInt64, Float32, Float64] - BUILTIN_INTEGER_TYPES = - [Int8, UInt8, Int16, UInt16, Int32, UInt32, Int64, UInt64] - BUILTIN_INTEGER_TYPES_128 = - [] of Int.class -{% end %} +BUILTIN_NUMBER_TYPES = + [Int8, UInt8, Int16, UInt16, Int32, UInt32, Int64, UInt64, Int128, UInt128, Float32, Float64] +BUILTIN_INTEGER_TYPES = + [Int8, UInt8, Int16, UInt16, Int32, UInt32, Int64, UInt64, Int128, UInt128] BUILTIN_INT_CONVERSIONS = { to_i: Int32, to_u: UInt32, to_i8: Int8, to_i16: Int16, to_i32: Int32, to_i64: Int64, to_i128: Int128, to_u8: UInt8, to_u16: UInt16, to_u32: UInt32, to_u64: UInt64, to_u128: UInt128, } - BUILTIN_NUMBER_TYPES_LTE_64 = [Int8, UInt8, Int16, UInt16, Int32, UInt32, Int64, UInt64, Float32, Float64] -BUILTIN_INTEGER_TYPES_LTE_64 = - [Int8, UInt8, Int16, UInt16, Int32, UInt32, Int64, UInt64] BUILTIN_FLOAT_TYPES = [Float32, Float64] diff --git a/src/crystal/compiler_rt.cr b/src/crystal/compiler_rt.cr index 6188177af311..c315e5037af9 100644 --- a/src/crystal/compiler_rt.cr +++ b/src/crystal/compiler_rt.cr @@ -9,3 +9,70 @@ require "./compiler_rt/divmod128.cr" # __multi3 was only missing on arm require "./compiler_rt/multi3.cr" {% end %} + +{% if flag?(:win32) && flag?(:bits64) %} + # LLVM doesn't honor the Windows x64 ABI when calling certain compiler-rt + # functions from its own instructions, but calls from Crystal do, so we invoke + # those functions directly + # note that the following defs redefine the ones in `primitives.cr` + + struct Int128 + {% for int2 in [Int8, Int16, Int32, Int64, Int128, UInt8, UInt16, UInt32, UInt64, UInt128] %} + @[AlwaysInline] + def unsafe_div(other : {{ int2.id }}) : self + __divti3(self, other.to_i128!) + end + + @[AlwaysInline] + def unsafe_mod(other : {{ int2.id }}) : self + __modti3(self, other.to_i128!) + end + {% end %} + end + + struct UInt128 + {% for int2 in [Int8, Int16, Int32, Int64, Int128, UInt8, UInt16, UInt32, UInt64, UInt128] %} + @[AlwaysInline] + def unsafe_div(other : {{ int2.id }}) : self + __udivti3(self, other.to_u128!) + end + + @[AlwaysInline] + def unsafe_mod(other : {{ int2.id }}) : self + __umodti3(self, other.to_u128!) + end + {% end %} + end + + {% for int1 in [Int8, Int16, Int32, Int64] %} + {% for int2 in [Int128, UInt128] %} + struct {{ int1.id }} + @[AlwaysInline] + def unsafe_div(other : {{ int2.id }}) : self + {{ int1.id }}.new!(__divti3(self.to_i128!, other.to_i128!)) + end + + @[AlwaysInline] + def unsafe_mod(other : {{ int2.id }}) : self + {{ int1.id }}.new!(__modti3(self.to_i128!, other.to_i128!)) + end + end + {% end %} + {% end %} + + {% for int1 in [UInt8, UInt16, UInt32, UInt64] %} + {% for int2 in [Int128, UInt128] %} + struct {{ int1.id }} + @[AlwaysInline] + def unsafe_div(other : {{ int2.id }}) : self + {{ int1.id }}.new!(__udivti3(self.to_u128!, other.to_u128!)) + end + + @[AlwaysInline] + def unsafe_mod(other : {{ int2.id }}) : self + {{ int1.id }}.new!(__umodti3(self.to_u128!, other.to_u128!)) + end + end + {% end %} + {% end %} +{% end %} diff --git a/src/prelude.cr b/src/prelude.cr index 79b5f838b03b..1b934882d374 100644 --- a/src/prelude.cr +++ b/src/prelude.cr @@ -23,6 +23,7 @@ require "steppable" require "indexable" require "string" require "number" +require "primitives" # Alpha-sorted list require "annotations" @@ -62,7 +63,6 @@ require "humanize" require "path" require "pointer" require "pretty_print" -require "primitives" require "proc" require "process" require "raise"