Allow large integer literals for DoubleWidth

This commit is contained in:
Nate Cook
2017-11-24 09:08:01 -06:00
parent 390d4464ad
commit abb75bca1a

View File

@@ -83,7 +83,10 @@ public struct DoubleWidth<Base : FixedWidthInteger> :
@_inlineable // FIXME(sil-serialize-all)
public init<T : BinaryInteger>(_ source: T) {
self.init(exactly: source)!
guard let result = DoubleWidth<Base>(exactly: source) else {
_preconditionFailure("Value is outside the representable range")
}
self = result
}
@_inlineable // FIXME(sil-serialize-all)
@@ -596,9 +599,42 @@ binaryOperators = [
// other
//
@_inlineable // FIXME(sil-serialize-all)
public init(_builtinIntegerLiteral x: _MaxBuiltinIntegerType) {
// FIXME: This won't work if `x` is out of range for `Int64`
self.init(Int64(_builtinIntegerLiteral: x))
public init(_builtinIntegerLiteral _x: _MaxBuiltinIntegerType) {
var _x = _x
self = DoubleWidth()
// If we can capture the entire literal in a single Int64, stop there.
// This avoids some potential deep recursion due to literal expressions in
// other DoubleWidth methods.
let (_value, _overflow) = Builtin.s_to_s_checked_trunc_Int2048_Int64(_x)
if !Bool(_overflow) {
self = DoubleWidth(Int64(_value))
return
}
// Convert all but the most significant 64 bits as unsigned integers.
let _shift = Builtin.sext_Int64_Int2048((64 as Int64)._value)
let lowWordCount = (bitWidth - 1) / 64
for i in 0..<lowWordCount {
let value =
DoubleWidth(UInt64(Builtin.s_to_u_checked_trunc_Int2048_Int64(_x).0))
&<< DoubleWidth(i * 64)
self |= value
_x = Builtin.ashr_Int2048(_x, _shift)
}
// Finally, convert the most significant 64 bits and check for overflow.
let overflow: Bool
if Base.isSigned {
let (_value, _overflow) = Builtin.s_to_s_checked_trunc_Int2048_Int64(_x)
self |= DoubleWidth(Int64(_value)) &<< DoubleWidth(lowWordCount * 64)
overflow = Bool(_overflow)
} else {
let (_value, _overflow) = Builtin.s_to_u_checked_trunc_Int2048_Int64(_x)
self |= DoubleWidth(UInt64(_value)) &<< DoubleWidth(lowWordCount * 64)
overflow = Bool(_overflow)
}
_precondition(!overflow, "Literal integer out of range for this type")
}
@_inlineable // FIXME(sil-serialize-all)