mirror of
https://github.com/apple/swift.git
synced 2025-12-14 20:36:38 +01:00
588 lines
17 KiB
Swift
588 lines
17 KiB
Swift
//===--- FixedPoint.swift.gyb ---------------------------------*- swift -*-===//
|
|
//
|
|
// This source file is part of the Swift.org open source project
|
|
//
|
|
// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors
|
|
// Licensed under Apache License v2.0 with Runtime Library Exception
|
|
//
|
|
// See http://swift.org/LICENSE.txt for license information
|
|
// See http://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
%{
|
|
|
|
from SwiftIntTypes import *
|
|
|
|
#
|
|
# Utility code for later in this template
|
|
#
|
|
def hexify(n):
|
|
"""Return a legible hex representation of n, using '_' separators """
|
|
z = '%X' % n
|
|
l = len(z)
|
|
r = []
|
|
while z:
|
|
r.insert(0, z[-4:])
|
|
z = z[:-4]
|
|
return '0x' + '_'.join(r)
|
|
|
|
# Number of bits in the Builtin.Word type
|
|
word_bits = int(CMAKE_SIZEOF_VOID_P) * 8
|
|
|
|
# Number of bits in integer literals.
|
|
builtinIntLiteralBits = 2048
|
|
|
|
# FIXME: checked and unchecked conversions of Word types
|
|
CastFromWord = 'zextOrBitCast_Word_Int64' if word_bits==64 else 'truncOrBitCast_Word_Int32'
|
|
CastToWord = 'truncOrBitCast_Int64_Word' if word_bits==64 else 'zextOrBitCast_Int32_Word'
|
|
|
|
def maskBits(n):
|
|
"""Return an n-bit mask in hex"""
|
|
return hexify((1 << n) - 1)
|
|
|
|
}%
|
|
|
|
public typealias IntMax = Int${int_max_bits}
|
|
public typealias UIntMax = UInt${int_max_bits}
|
|
|
|
/// This protocol is an implementation detail of `IntegerType`; do
|
|
/// not use it directly.
|
|
///
|
|
/// Its requirements are inherited by `IntegerType` and thus must
|
|
/// be satisfied by types conforming to that protocol.
|
|
public protocol _IntegerType
|
|
: _BuiltinIntegerLiteralConvertible,
|
|
IntegerLiteralConvertible,
|
|
Printable,
|
|
Hashable,
|
|
IntegerArithmeticType,
|
|
BitwiseOperationsType,
|
|
_Incrementable
|
|
{
|
|
}
|
|
|
|
/// A set of common requirements for Swift's integer types.
|
|
public protocol IntegerType : _IntegerType, RandomAccessIndexType {
|
|
}
|
|
|
|
/// This protocol is an implementation detail of `SignedIntegerType`;
|
|
/// do not use it directly.
|
|
///
|
|
/// Its requirements are inherited by `SignedIntegerType` and thus
|
|
/// must be satisfied by types conforming to that protocol.
|
|
public protocol _SignedIntegerType : _IntegerType, SignedNumberType {
|
|
/// Represent this number using Swift's widest native signed integer
|
|
/// type.
|
|
func toIntMax() -> IntMax
|
|
|
|
/// Convert from Swift's widest signed integer type, trapping on
|
|
/// overflow.
|
|
init(IntMax)
|
|
}
|
|
|
|
/// A set of common requirements for Swift's signed integer types.
|
|
public protocol SignedIntegerType : _SignedIntegerType, IntegerType {
|
|
}
|
|
|
|
/// This protocol is an implementation detail of `SignedIntegerType`;
|
|
/// do not use it directly.
|
|
///
|
|
/// Its requirements are inherited by `SignedIntegerType` and thus
|
|
/// must be satisfied by types conforming to that protocol.
|
|
public protocol _UnsignedIntegerType : _IntegerType {
|
|
/// Represent this number using Swift's widest native unsigned
|
|
/// integer type.
|
|
func toUIntMax() -> UIntMax
|
|
|
|
/// Convert from Swift's widest unsigned integer type, trapping on
|
|
/// overflow.
|
|
init(UIntMax)
|
|
}
|
|
|
|
/// A set of common requirements for Swift's unsigned integer types.
|
|
public protocol UnsignedIntegerType : _UnsignedIntegerType, IntegerType {
|
|
}
|
|
|
|
public func numericCast<
|
|
T : _SignedIntegerType, U : _SignedIntegerType
|
|
>(x: T) -> U {
|
|
return U(x.toIntMax())
|
|
}
|
|
|
|
public func numericCast<
|
|
T : _UnsignedIntegerType, U : _UnsignedIntegerType
|
|
>(x: T) -> U {
|
|
return U(x.toUIntMax())
|
|
}
|
|
|
|
public func numericCast<
|
|
T : _SignedIntegerType, U : _UnsignedIntegerType
|
|
>(x: T) -> U {
|
|
return U(UIntMax(x.toIntMax()))
|
|
}
|
|
|
|
public func numericCast<
|
|
T : _UnsignedIntegerType, U : _SignedIntegerType
|
|
>(x: T) -> U {
|
|
return U(IntMax(x.toUIntMax()))
|
|
}
|
|
|
|
% for self_ty in all_integer_types(word_bits):
|
|
% bits = self_ty.bits
|
|
% signed = self_ty.is_signed
|
|
% (sign, ext) = ('s', 'sext') if signed else ('u', 'zext')
|
|
% Self = self_ty.stdlib_name
|
|
% BuiltinName = self_ty.builtin_name
|
|
% OtherSelf = self_ty.get_opposite_signedness().stdlib_name
|
|
|
|
public struct ${Self}
|
|
: ${'SignedIntegerType' if sign == 's' else 'UnsignedIntegerType'} {
|
|
public var value: Builtin.${BuiltinName}
|
|
|
|
// FIXME: this declaration should be inferred.
|
|
// <rdar://problem/18379938> Type checker refuses to use the default for
|
|
// Int.Distance associated type
|
|
|
|
/// A type that can represent the number of steps between pairs of
|
|
/// values.
|
|
public typealias Distance = Int
|
|
|
|
/// Create an instance initialized to zero.
|
|
@transparent public
|
|
init() {
|
|
var maxWidthZero: IntMax = 0
|
|
value = Builtin.truncOrBitCast_Int${int_max_bits}_${BuiltinName}(
|
|
maxWidthZero.value)
|
|
}
|
|
|
|
@transparent public
|
|
init(_ v: Builtin.${BuiltinName}) {
|
|
value = v
|
|
}
|
|
|
|
/// Create an instance initialized to `value`.
|
|
@transparent public
|
|
init(_ value: ${Self}) { self = value }
|
|
|
|
% if bits > 8:
|
|
/// Creates an integer from its big-endian representation, changing the
|
|
/// byte order if necessary.
|
|
@transparent public
|
|
init(bigEndian value: ${Self}) {
|
|
#if arch(i386) || arch(x86_64) || arch(arm) || arch(arm64)
|
|
self = ${Self}(Builtin.int_bswap_${BuiltinName}(value.value) )
|
|
#else
|
|
_UnsupportedArchitectureError()
|
|
#endif
|
|
}
|
|
|
|
/// Creates an integer from its little-endian representation, changing the
|
|
/// byte order if necessary.
|
|
@transparent public
|
|
init(littleEndian value: ${Self}) {
|
|
#if arch(i386) || arch(x86_64) || arch(arm) || arch(arm64)
|
|
self = value
|
|
#else
|
|
_UnsupportedArchitectureError()
|
|
#endif
|
|
}
|
|
% end
|
|
|
|
@transparent public
|
|
init(_builtinIntegerLiteral value: Builtin.Int${builtinIntLiteralBits}) {
|
|
self = ${Self}(Builtin.s_to_${sign}_checked_trunc_Int${builtinIntLiteralBits}_${BuiltinName}(value).0)
|
|
}
|
|
|
|
/// Create an instance initialized to `value`.
|
|
@transparent public
|
|
init(integerLiteral value: ${Self}) {
|
|
self = value
|
|
}
|
|
|
|
% if bits > 8:
|
|
/// Returns the big-endian representation of the integer, changing the
|
|
/// byte order if necessary.
|
|
public var bigEndian: ${Self} {
|
|
#if arch(i386) || arch(x86_64) || arch(arm) || arch(arm64)
|
|
return ${Self}(Builtin.int_bswap_${BuiltinName}(value) )
|
|
#else
|
|
_UnsupportedArchitectureError()
|
|
#endif
|
|
}
|
|
/// Returns the little-endian representation of the integer, changing the
|
|
/// byte order if necessary.
|
|
public var littleEndian: ${Self} {
|
|
#if arch(i386) || arch(x86_64) || arch(arm) || arch(arm64)
|
|
return self
|
|
#else
|
|
_UnsupportedArchitectureError()
|
|
#endif
|
|
}
|
|
% end
|
|
|
|
% if bits > 8:
|
|
/// Returns the current integer with the byte order swapped.
|
|
public var byteSwapped: ${Self} {
|
|
return ${Self}(Builtin.int_bswap_${BuiltinName}(value))
|
|
}
|
|
% end
|
|
|
|
% max = maskBits((bits - 1) if signed else bits)
|
|
@transparent public
|
|
static var max: ${Self} { return ${max} }
|
|
@transparent public
|
|
static var min: ${Self} { return ${'-%s-1' % max if signed else '0'} }
|
|
@transparent
|
|
public static var _sizeInBits: ${Self} { return ${bits} }
|
|
}
|
|
|
|
extension ${Self} : Hashable {
|
|
public var hashValue: Int {
|
|
% if bits < word_bits:
|
|
return Int(Builtin.sextOrBitCast_${BuiltinName}_Word(self.value))
|
|
% elif self_ty.is_word:
|
|
return Int(self.value)
|
|
% elif bits == word_bits:
|
|
return Int(Builtin.${CastToWord}(self.value))
|
|
% elif bits == word_bits * 2:
|
|
return
|
|
Int(truncatingBitPattern: self) ^
|
|
Int(truncatingBitPattern: self >> 32)
|
|
% else:
|
|
_Unimplemented()
|
|
% end
|
|
}
|
|
}
|
|
|
|
extension ${Self} : Printable {
|
|
public var description: String {
|
|
% if signed:
|
|
return _int64ToString(self.toIntMax())
|
|
% else:
|
|
return _uint64ToString(self.toUIntMax())
|
|
% end
|
|
}
|
|
}
|
|
|
|
// When ${Self} is used as an index, there are always bounds---more
|
|
// restrictive than the full range of ${Self}---against which we're
|
|
// not able to check. Overflows are not useful indicators of
|
|
// precondition violations in this context. Therefore, we use masked
|
|
// arithmetic in this conformance, and we need to be be sure that
|
|
// generic implementations of the arithmetic operators for
|
|
// RandomAccessIndexType's are all shadowed by more-specific
|
|
// implementations that *do* check for overflows.
|
|
@transparent
|
|
extension ${Self} : RandomAccessIndexType {
|
|
// HACK: Disable indexing and slicing Ranges of IntegerType types
|
|
// outside of a generic context. See the implementation of Range
|
|
// for details of how this works.
|
|
typealias _DisabledRangeIndex = ${Self}
|
|
|
|
/// Returns the next consecutive value after `self`.
|
|
///
|
|
/// Requires: the next value is representable.
|
|
@transparent public
|
|
func successor() -> ${Self} {
|
|
return self &+ 1
|
|
}
|
|
/// Returns the previous consecutive value before `self`.
|
|
///
|
|
/// Requires: the previous value is representable.
|
|
@transparent public
|
|
func predecessor() -> ${Self} {
|
|
return self &- 1
|
|
}
|
|
|
|
/// Return the minimum number of applications of `successor` or
|
|
/// `predecessor` required to reach `other` from `self`.
|
|
///
|
|
/// Complexity: O(1).
|
|
@transparent public
|
|
func distanceTo(other: ${Self}) -> ${Self}.Distance {
|
|
return numericCast((numericCast(other) as IntMax) &- numericCast(self))
|
|
}
|
|
|
|
/// Return `self` offset by `n` steps.
|
|
///
|
|
/// :returns: If `n > 0`, the result of applying `successor` to
|
|
/// `self` `n` times. If `n < 0`, the result of applying
|
|
/// `predecessor` to `self` `-n` times. Otherwise, `self`.
|
|
///
|
|
/// Complexity: O(1)
|
|
@transparent public
|
|
func advancedBy(amount: ${Self}.Distance) -> ${Self} {
|
|
return numericCast((numericCast(self) as IntMax) &+ numericCast(amount))
|
|
}
|
|
}
|
|
|
|
// Operations that return an overflow bit in addition to a partial result,
|
|
// helpful for checking for overflow when you want to handle it.
|
|
extension ${Self} {
|
|
% for Method,op in [('add', 'add'), ('subtract', 'sub'), ('multiply', 'mul')]:
|
|
/// ${Method.capitalize()} `lhs` and `rhs`, returning a result and a
|
|
/// `Bool` that is true iff the operation caused an arithmetic
|
|
/// overflow.
|
|
@transparent public
|
|
static func ${Method}WithOverflow(lhs: ${Self}, _ rhs: ${Self}) -> (${Self}, overflow: Bool) {
|
|
var tmp = Builtin.${sign}${op}_with_overflow_${BuiltinName}(lhs.value, rhs.value, false.value)
|
|
return (${Self}(tmp.0), Bool(tmp.1))
|
|
}
|
|
% end
|
|
|
|
% for Method,op in [('divide', 'div'), ('remainder', 'rem')]:
|
|
/// Divide `lhs` and `rhs`, returning
|
|
/// ${'a result' if op == 'div' else 'the remainder'} and a `Bool`
|
|
/// that is true iff the operation caused an arithmetic overflow.
|
|
@transparent public
|
|
static func ${Method}WithOverflow(lhs: ${Self}, _ rhs: ${Self}) -> (${Self}, overflow: Bool) {
|
|
if rhs == 0 {
|
|
return (0, true)
|
|
}
|
|
% if signed:
|
|
if lhs == ${Self}.min && rhs == -1 {
|
|
return (0, true)
|
|
}
|
|
% end
|
|
// FIXME: currently doesn't detect overflow -- blocked by:
|
|
// <rdar://15735295> Need [su]{div,rem}_with_overflow IR
|
|
var tmp = Builtin.${sign}${op}_${BuiltinName}(lhs.value, rhs.value)
|
|
return (${Self}(tmp), false)
|
|
}
|
|
%end
|
|
|
|
% (U, un) = ('','') if signed else ('U','un')
|
|
/// Represent this number using Swift's widest native ${un}signed
|
|
/// integer type.
|
|
@transparent public
|
|
func to${U}IntMax() -> ${U}IntMax {
|
|
return ${'self' if Self == U+'Int%s'%int_max_bits else U+'IntMax(self)'}
|
|
}
|
|
% if not signed:
|
|
/// Explicitly convert to `IntMax`${', trapping on overflow (except in -Ounchecked builds)' if bits == int_max_bits else ''}.
|
|
@transparent public
|
|
func toIntMax() -> IntMax {
|
|
return IntMax(toUIntMax())
|
|
}
|
|
% end
|
|
}
|
|
|
|
% if signed:
|
|
@transparent
|
|
extension ${Self} : SignedNumberType {}
|
|
% end
|
|
|
|
%# FIXME: checked conversions of Word types
|
|
// construction from other integer types
|
|
@transparent
|
|
extension ${Self} {
|
|
% for src_ty in all_integer_types(word_bits):
|
|
% srcBits = src_ty.bits
|
|
% srcSigned = src_ty.is_signed
|
|
% Src = src_ty.stdlib_name
|
|
% srcBuiltinName = src_ty.builtin_name
|
|
% (srcSign, srcExt) = ('s', 'sext') if srcSigned else ('u', 'zext')
|
|
% if Self != Src:
|
|
public init(_ v: ${Src}) {
|
|
%
|
|
% if srcBuiltinName == 'Word':
|
|
var srcNotWord = Builtin.${CastFromWord}(v.value)
|
|
% else:
|
|
var srcNotWord = v.value
|
|
% end
|
|
%
|
|
% if srcBits == bits and srcSign == sign:
|
|
var dstNotWord = srcNotWord
|
|
%
|
|
% elif srcBits == bits:
|
|
var tmp = Builtin.${srcSign}_to_${sign}_checked_conversion_Int${srcBits}(srcNotWord)
|
|
Builtin.condfail(tmp.1)
|
|
var dstNotWord = tmp.0
|
|
%
|
|
% elif srcBits > bits:
|
|
var tmp = Builtin.${srcSign}_to_${sign}_checked_trunc_Int${srcBits}_Int${bits}(srcNotWord)
|
|
Builtin.condfail(tmp.1)
|
|
var dstNotWord = tmp.0
|
|
%
|
|
% elif srcSigned and not signed:
|
|
var tmp = Builtin.s_to_u_checked_conversion_Int${srcBits}(srcNotWord)
|
|
Builtin.condfail(tmp.1)
|
|
var dstNotWord = Builtin.${srcExt}_Int${srcBits}_Int${bits}(tmp.0)
|
|
%
|
|
% else:
|
|
var dstNotWord = Builtin.${srcExt}_Int${srcBits}_Int${bits}(srcNotWord)
|
|
% end
|
|
%
|
|
% if BuiltinName == 'Word':
|
|
value = Builtin.${CastToWord}(dstNotWord)
|
|
% else:
|
|
value = dstNotWord
|
|
% end
|
|
}
|
|
% end
|
|
|
|
% if should_define_truncating_bit_pattern_init(src_ty=src_ty, dst_ty=self_ty):
|
|
/// Construct a `${Self}` having the same bitwise representation as
|
|
/// the least significant bits of the provided bit pattern.
|
|
///
|
|
/// No range or overflow checking occurs.
|
|
@transparent
|
|
public init(truncatingBitPattern: ${Src}) {
|
|
%
|
|
% if srcBuiltinName == 'Word':
|
|
let srcNotWord = Builtin.${CastFromWord}(truncatingBitPattern.value)
|
|
% else:
|
|
let srcNotWord = truncatingBitPattern.value
|
|
% end
|
|
%
|
|
% if self_ty.bits == src_ty.bits:
|
|
let dstNotWord = srcNotWord
|
|
% else:
|
|
let dstNotWord = Builtin.trunc_Int${srcBits}_Int${bits}(srcNotWord)
|
|
% end
|
|
%
|
|
% if BuiltinName == 'Word':
|
|
value = Builtin.${CastToWord}(dstNotWord)
|
|
% else:
|
|
value = dstNotWord
|
|
% end
|
|
}
|
|
|
|
% end
|
|
% end
|
|
|
|
/// Construct a `${Self}` having the same memory representation as
|
|
/// the `${OtherSelf}` `bitPattern`. No range or overflow checking
|
|
/// occurs, and the resulting `${Self}` may not have the same numeric
|
|
/// value as `bitPattern`--it is only guaranteed to use the same
|
|
/// pattern of bits.
|
|
@transparent
|
|
public init(bitPattern: ${OtherSelf}) {
|
|
value = bitPattern.value
|
|
}
|
|
}
|
|
|
|
// Operations with potentially-static overflow checking
|
|
//
|
|
// FIXME: must use condfail in these operators, rather than
|
|
// overflowChecked, pending <rdar://problem/16271923> so that we don't
|
|
// foil static checking for numeric overflows.
|
|
% for op,method in ('+','add'), ('*','mul'), ('-','sub'):
|
|
@transparent public
|
|
func ${op} (lhs: ${Self}, rhs: ${Self}) -> ${Self} {
|
|
let (result, error) = Builtin.${sign}${method}_with_overflow_${BuiltinName}(
|
|
lhs.value, rhs.value, true.value)
|
|
// return overflowChecked((${Self}(result), Bool(error)))
|
|
Builtin.condfail(error)
|
|
return ${Self}(result)
|
|
}
|
|
% end
|
|
|
|
% for op,inst in [('/', 'div'), ('%', 'rem')]:
|
|
@transparent public
|
|
func ${op}(lhs: ${Self}, rhs: ${Self}) -> ${Self} {
|
|
Builtin.condfail((rhs == 0).value)
|
|
% if signed:
|
|
Builtin.condfail(((lhs == ${Self}.min) & (rhs == -1)).value)
|
|
% end
|
|
// FIXME: currently doesn't detect overflow -- blocked by:
|
|
// <rdar://15735295> Need [su]{div,rem}_with_overflow IR
|
|
var tmp = Builtin.${sign}${inst}_${BuiltinName}(lhs.value, rhs.value)
|
|
return ${Self}(tmp)
|
|
}
|
|
%end
|
|
|
|
// Bitwise negate
|
|
@transparent public
|
|
prefix func ~(rhs: ${Self}) -> ${Self} {
|
|
let mask = ${Self}.subtractWithOverflow(0, 1).0
|
|
return ${Self}(Builtin.xor_${BuiltinName}(rhs.value, mask.value))
|
|
}
|
|
|
|
% for op, name in (
|
|
% ('==','eq'), ('!=','ne'),
|
|
% ('<',sign+'lt'), ('<=',sign+'le'),
|
|
% ('>',sign+'gt'), ('>=',sign+'ge')):
|
|
@transparent public
|
|
func ${op} (lhs: ${Self}, rhs: ${Self}) -> Bool {
|
|
return Bool(Builtin.cmp_${name}_${BuiltinName}(lhs.value, rhs.value))
|
|
}
|
|
% end
|
|
|
|
% for op, name in (('<<','shl'), ('>>','ashr' if signed else 'lshr')):
|
|
@transparent public
|
|
func ${op} (lhs: ${Self}, rhs: ${Self}) -> ${Self} {
|
|
% if signed:
|
|
_precondition(U${Self}(rhs) < U${Self}._sizeInBits,
|
|
"shift amount is larger than type size in bits")
|
|
% else:
|
|
_precondition(rhs < ${Self}._sizeInBits,
|
|
"shift amount is larger than type size in bits")
|
|
% end
|
|
return ${Self}(Builtin.${name}_${BuiltinName}(lhs.value, rhs.value))
|
|
}
|
|
% end
|
|
|
|
% for op, name in (('&','and'), ('^','xor'), ('|','or')):
|
|
@transparent public
|
|
func ${op} (lhs: ${Self}, rhs: ${Self}) -> ${Self} {
|
|
return ${Self}(Builtin.${name}_${BuiltinName}(lhs.value, rhs.value))
|
|
}
|
|
% end
|
|
|
|
// bitwise operations
|
|
@transparent
|
|
extension ${Self} : BitwiseOperationsType {
|
|
public static var allZeros: ${Self} { return 0 }
|
|
}
|
|
|
|
// Compound assignments
|
|
% for op in '+', '-', '*', '<<', '>>', '&', '|', '^':
|
|
@transparent public
|
|
func ${op}=(inout lhs: ${Self}, rhs: ${Self}) {
|
|
lhs = lhs ${op} rhs
|
|
}
|
|
% end
|
|
|
|
// Prefix and postfix increment and decrement.
|
|
|
|
// We already have generic versions of these, but when compiling
|
|
// -Onone we are unable to devirtualize the generic call, which
|
|
// results in worse performance than we would like for these simple
|
|
// operations (tracked by <rdar://problem/17692569>).
|
|
@transparent
|
|
public prefix func ++ (inout x: ${Self}) -> ${Self} {
|
|
x = x + 1
|
|
return x
|
|
}
|
|
|
|
@transparent
|
|
public postfix func ++ (inout x: ${Self}) -> ${Self} {
|
|
var ret = x
|
|
x = x + 1
|
|
return ret
|
|
}
|
|
|
|
@transparent
|
|
public prefix func -- (inout x: ${Self}) -> ${Self} {
|
|
x = x - 1
|
|
return x
|
|
}
|
|
|
|
@transparent
|
|
public postfix func -- (inout x: ${Self}) -> ${Self} {
|
|
var ret = x
|
|
x = x - 1
|
|
return ret
|
|
}
|
|
|
|
% end # for bits in allInts
|
|
|
|
public typealias Word = Int
|
|
public typealias UWord = UInt
|
|
|
|
// ${'Local Variables'}:
|
|
// eval: (read-only-mode 1)
|
|
// End:
|