mirror of
https://github.com/apple/swift.git
synced 2025-12-14 20:36:38 +01:00
Using the unknown-sized Builtin.Word types complicates producing compile-time overflow diagnostics. If we don't know the target Word size, we don't know if there is an overflow. But SIL optimizer does not know the size of Word, this is the point of having the Word type in the first place. Also, this opens up more possibilities for optimizations. rdar://17604532 Swift SVN r24788
655 lines
19 KiB
Swift
655 lines
19 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
|
|
|
|
def maskBits(n):
|
|
"""Return an n-bit mask in hex"""
|
|
return hexify((1 << n) - 1)
|
|
|
|
}%
|
|
|
|
/// The largest native signed integer type
|
|
public typealias IntMax = Int${int_max_bits}
|
|
/// The largest native unsigned integer type
|
|
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 {
|
|
// Used to create a deliberate ambiguity in cases like UInt(1) +
|
|
// Int(1), which would otherwise compile due to the arithmetic
|
|
// operators defined for Strideable types (unsigned types are
|
|
// Strideable).
|
|
typealias _DisallowMixedSignArithmetic : SignedIntegerType = Int
|
|
|
|
/// 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 {
|
|
}
|
|
|
|
/// Convert `x` to type `U`, trapping on overflow in -Onone and -O
|
|
/// builds.
|
|
///
|
|
/// Typically used to do conversion to any contextually-deduced
|
|
/// integer type::
|
|
///
|
|
/// func f(x: Int32) {}
|
|
/// func g(x: Int64) { f(numericCast(x)) }
|
|
public func numericCast<
|
|
T : _SignedIntegerType, U : _SignedIntegerType
|
|
>(x: T) -> U {
|
|
return U(x.toIntMax())
|
|
}
|
|
|
|
/// Convert `x` to type `U`, trapping on overflow in -Onone and -O
|
|
/// builds.
|
|
///
|
|
/// Typically used to do conversion to any contextually-deduced
|
|
/// integer type::
|
|
///
|
|
/// func f(x: UInt32) {}
|
|
/// func g(x: UInt64) { f(numericCast(x)) }
|
|
public func numericCast<
|
|
T : _UnsignedIntegerType, U : _UnsignedIntegerType
|
|
>(x: T) -> U {
|
|
return U(x.toUIntMax())
|
|
}
|
|
|
|
/// Convert `x` to type `U`, trapping on overflow in -Onone and -O
|
|
/// builds.
|
|
///
|
|
/// Typically used to do conversion to any contextually-deduced
|
|
/// integer type::
|
|
///
|
|
/// func f(x: UInt32) {}
|
|
/// func g(x: Int64) { f(numericCast(x)) }
|
|
public func numericCast<
|
|
T : _SignedIntegerType, U : _UnsignedIntegerType
|
|
>(x: T) -> U {
|
|
return U(UIntMax(x.toIntMax()))
|
|
}
|
|
|
|
/// Convert `x` to type `U`, trapping on overflow in -Onone and -O
|
|
/// builds.
|
|
///
|
|
/// Typically used to do conversion to any contextually-deduced
|
|
/// integer type::
|
|
///
|
|
/// func f(x: Int32) {}
|
|
/// func g(x: UInt64) { f(numericCast(x)) }
|
|
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
|
|
|
|
/// A ${bits}-bit ${'un' if sign == 'u' else ''}signed integer value
|
|
/// type.
|
|
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() {
|
|
let maxWidthZero: IntMax = 0
|
|
value = Builtin.truncOrBitCast_Int${int_max_bits}_${BuiltinName}(
|
|
maxWidthZero.value)
|
|
}
|
|
|
|
@transparent public
|
|
init(_ _v: Builtin.${BuiltinName}) {
|
|
value = _v
|
|
}
|
|
|
|
% if self_ty.is_word:
|
|
@transparent
|
|
public // @testable
|
|
init(_ v: Builtin.Word) {
|
|
% if BuiltinName == 'Int32':
|
|
value = Builtin.truncOrBitCast_Word_Int32(v)
|
|
% elif BuiltinName == 'Int64':
|
|
value = Builtin.zextOrBitCast_Word_Int64(v)
|
|
% end
|
|
}
|
|
|
|
@transparent
|
|
public // @testable
|
|
var _builtinWordValue: Builtin.Word {
|
|
% if BuiltinName == 'Int32':
|
|
return Builtin.zextOrBitCast_Int32_Word(value)
|
|
% elif BuiltinName == 'Int64':
|
|
return Builtin.truncOrBitCast_Int64_Word(value)
|
|
% end
|
|
}
|
|
% end
|
|
|
|
/// 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 {
|
|
/// The hash value.
|
|
///
|
|
/// **Axiom:** `x == y` implies `x.hashValue == y.hashValue`
|
|
///
|
|
/// **Note:** the hash value is not guaranteed to be stable across
|
|
/// different invocations of the same program. Do not persist the
|
|
/// hash value across program runs.
|
|
public var hashValue: Int {
|
|
% if bits <= word_bits and signed:
|
|
// Sign extend the value.
|
|
return Int(self)
|
|
% elif bits <= word_bits and not signed:
|
|
// Sign extend the value.
|
|
return Int(${OtherSelf}(bitPattern: self))
|
|
% elif bits == word_bits * 2:
|
|
// We have twice as many bits as we need to return.
|
|
return
|
|
Int(truncatingBitPattern: self) ^
|
|
Int(truncatingBitPattern: self >> 32)
|
|
% else:
|
|
_Unimplemented()
|
|
% end
|
|
}
|
|
}
|
|
|
|
extension ${Self} : Printable {
|
|
/// A textual representation of `self`.
|
|
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) {
|
|
let 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
|
|
let 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
|
|
% (srcSign, srcExt) = ('s', 'sext') if srcSigned else ('u', 'zext')
|
|
% if Self != Src:
|
|
public init(_ v: ${Src}) {
|
|
%
|
|
let srcNotWord = v.value
|
|
%
|
|
% if srcBits == bits and srcSign == sign:
|
|
let dstNotWord = srcNotWord
|
|
%
|
|
% elif srcBits == bits:
|
|
let tmp = Builtin.${srcSign}_to_${sign}_checked_conversion_Int${srcBits}(srcNotWord)
|
|
Builtin.condfail(tmp.1)
|
|
let dstNotWord = tmp.0
|
|
%
|
|
% elif srcBits > bits:
|
|
let tmp = Builtin.${srcSign}_to_${sign}_checked_trunc_Int${srcBits}_Int${bits}(srcNotWord)
|
|
Builtin.condfail(tmp.1)
|
|
let dstNotWord = tmp.0
|
|
%
|
|
% elif srcSigned and not signed:
|
|
let tmp = Builtin.s_to_u_checked_conversion_Int${srcBits}(srcNotWord)
|
|
Builtin.condfail(tmp.1)
|
|
let dstNotWord = Builtin.${srcExt}_Int${srcBits}_Int${bits}(tmp.0)
|
|
%
|
|
% else:
|
|
let dstNotWord = Builtin.${srcExt}_Int${srcBits}_Int${bits}(srcNotWord)
|
|
% end
|
|
%
|
|
value = dstNotWord
|
|
}
|
|
% 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}) {
|
|
%
|
|
let srcNotWord = truncatingBitPattern.value
|
|
%
|
|
% if self_ty.bits == src_ty.bits:
|
|
let dstNotWord = srcNotWord
|
|
% else:
|
|
let dstNotWord = Builtin.trunc_Int${srcBits}_Int${bits}(srcNotWord)
|
|
% end
|
|
%
|
|
value = dstNotWord
|
|
}
|
|
|
|
% 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
|
|
let 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 {
|
|
/// The empty bitset of type ${Self}.
|
|
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
|
|
}
|
|
|
|
% if signed:
|
|
// TODO: Consider removing the underscore.
|
|
/// Returns the argument and specifies that the value is not negative.
|
|
/// It has only an effect if the argument is a load or call.
|
|
@transparent
|
|
public func _assumeNonNegative(x: ${Self}) -> ${Self} {
|
|
_sanityCheck(x >= 0)
|
|
return ${Self}(Builtin.assumeNonNegative_${BuiltinName}(x.value))
|
|
}
|
|
% end
|
|
|
|
% end # for bits in allInts
|
|
|
|
/// A signed integer type that occupies one machine word
|
|
public typealias Word = Int
|
|
|
|
/// An unsigned integer type that occupies one machine word
|
|
public typealias UWord = UInt
|
|
|
|
// ${'Local Variables'}:
|
|
// eval: (read-only-mode 1)
|
|
// End:
|