Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 4 additions & 6 deletions spec/primitives/int_spec.cr
Original file line number Diff line number Diff line change
Expand Up @@ -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
3 changes: 1 addition & 2 deletions spec/std/crystal/hasher_spec.cr
Original file line number Diff line number Diff line change
Expand Up @@ -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
Comment thread
straight-shoota marked this conversation as resolved.
{% 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
Expand Down
39 changes: 10 additions & 29 deletions spec/std/int_spec.cr
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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}})
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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
Expand Down
32 changes: 16 additions & 16 deletions spec/std/string_spec.cr
Original file line number Diff line number Diff line change
Expand Up @@ -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) }
Expand Down
23 changes: 4 additions & 19 deletions spec/support/number.cr
Original file line number Diff line number Diff line change
@@ -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]

Expand Down
67 changes: 67 additions & 0 deletions src/crystal/compiler_rt.cr
Original file line number Diff line number Diff line change
Expand Up @@ -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) %}
Comment thread
HertzDevil marked this conversation as resolved.
# 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 %}
2 changes: 1 addition & 1 deletion src/prelude.cr
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ require "steppable"
require "indexable"
require "string"
require "number"
require "primitives"

# Alpha-sorted list
require "annotations"
Expand Down Expand Up @@ -62,7 +63,6 @@ require "humanize"
require "path"
require "pointer"
require "pretty_print"
require "primitives"
require "proc"
require "process"
require "raise"
Expand Down