mirror of
https://github.com/apple/swift.git
synced 2025-12-21 12:14:44 +01:00
This is motivated by <rdar://problem/17051606>. This ends up renaming variables as well, which seems right for consistency since we use "predicate" as variable name. Swift SVN r19135
468 lines
12 KiB
Swift
468 lines
12 KiB
Swift
%# -*- mode: swift -*-
|
|
|
|
%# Ignore the following admonition; it applies to the resulting .swift file only
|
|
//// Automatically Generated From FixedPoint.gyb. Do Not Edit Directly!
|
|
//===----------------------------------------------------------------------===//
|
|
//
|
|
// 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
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
%{
|
|
#
|
|
# 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)
|
|
|
|
|
|
# Bit counts for all int types
|
|
allNames = [8, 16, 32, 64, 'Int']
|
|
|
|
# Number of bits in the biggest int type
|
|
maxBits = 64
|
|
|
|
# Number of bits in the Builtin.Word type
|
|
wordBits = 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 wordBits==64 else 'truncOrBitCast_Word_Int32'
|
|
CastToWord = 'truncOrBitCast_Int64_Word' if wordBits==64 else 'zextOrBitCast_Int32_Word'
|
|
|
|
def maskBits(n):
|
|
"""Return an n-bit mask in hex"""
|
|
return hexify((1 << n) - 1)
|
|
|
|
def allInts():
|
|
for name in allNames:
|
|
for signed in False, True:
|
|
yield str(name), int(wordBits if name=='Int' else name), signed
|
|
|
|
def baseIntName(name):
|
|
return 'Int' if name == 'Int' else 'Int' + str(name)
|
|
|
|
def builtinIntName(name):
|
|
return 'Word' if name == 'Int' else 'Int' + str(name)
|
|
|
|
def intName(name, signed):
|
|
return ('' if signed else 'U') + baseIntName(name)
|
|
|
|
def otherIntName(name, signed):
|
|
return ('U' if signed else '') + baseIntName(name)
|
|
}%
|
|
|
|
typealias IntMax = Int${maxBits}
|
|
typealias UIntMax = UInt${maxBits}
|
|
|
|
protocol _Integer
|
|
: _BuiltinIntegerLiteralConvertible,
|
|
IntegerLiteralConvertible,
|
|
Printable,
|
|
ArrayBound,
|
|
Hashable,
|
|
IntegerArithmetic,
|
|
BitwiseOperations,
|
|
_Incrementable
|
|
{
|
|
}
|
|
|
|
protocol Integer : _Integer, RandomAccessIndex {
|
|
}
|
|
|
|
protocol _SignedInteger : _Integer, SignedNumber {
|
|
func toIntMax() -> IntMax
|
|
class func from(IntMax) -> Self
|
|
}
|
|
|
|
protocol SignedInteger : _SignedInteger, Integer {
|
|
}
|
|
|
|
protocol _UnsignedInteger : _Integer {
|
|
func toUIntMax() -> UIntMax
|
|
class func from(UIntMax) -> Self
|
|
}
|
|
|
|
protocol UnsignedInteger : _UnsignedInteger, Integer {
|
|
}
|
|
|
|
func numericCast<T : _SignedInteger, U : _SignedInteger>(x: T) -> U {
|
|
return .from(x.toIntMax())
|
|
}
|
|
|
|
func numericCast<T : _UnsignedInteger, U : _UnsignedInteger>(x: T) -> U {
|
|
return .from(x.toUIntMax())
|
|
}
|
|
|
|
func numericCast<T : _SignedInteger, U : _UnsignedInteger>(x: T) -> U {
|
|
return .from(UIntMax(x.toIntMax()))
|
|
}
|
|
|
|
func numericCast<T : _UnsignedInteger, U : _SignedInteger>(x: T) -> U {
|
|
return .from(IntMax(x.toUIntMax()))
|
|
}
|
|
|
|
% for (name, bits, signed) in allInts():
|
|
% (sign, ext) = ('s', 'sext') if signed else ('u', 'zext')
|
|
% BuiltinName = builtinIntName(name)
|
|
% Self = intName(name, signed)
|
|
% OtherSelf = otherIntName(name, signed)
|
|
% ConstructIntType = 'Int' if Self != 'Int' else ''
|
|
|
|
struct ${Self} : ${'SignedInteger' if sign == 's' else 'UnsignedInteger'} {
|
|
var value: Builtin.${BuiltinName}
|
|
|
|
@transparent
|
|
init() {
|
|
var maxWidthZero: IntMax = 0
|
|
value = Builtin.truncOrBitCast_Int${maxBits}_${BuiltinName}(maxWidthZero.value)
|
|
}
|
|
|
|
@transparent
|
|
init(_ v: Builtin.${BuiltinName}) {
|
|
value = v
|
|
}
|
|
|
|
@transparent
|
|
init(_ value: ${Self}) { self = value }
|
|
|
|
% if bits > 8:
|
|
/// Creates an integer from its big-endian representation, changing the
|
|
/// byte order if necessary.
|
|
@transparent
|
|
init(bigEndian value: ${Self}) {
|
|
#if arch(i386) || arch(x86_64) || arch(arm) || arch(arm64)
|
|
self = ${Self}(Builtin.int_bswap_${BuiltinName}(value.value) )
|
|
#else
|
|
assert(false)
|
|
#endif
|
|
}
|
|
|
|
/// Creates an integer from its little-endian representation, changing the
|
|
/// byte order if necessary.
|
|
@transparent
|
|
init(littleEndian value: ${Self}) {
|
|
#if arch(i386) || arch(x86_64) || arch(arm) || arch(arm64)
|
|
self = value
|
|
#else
|
|
assert(false)
|
|
#endif
|
|
}
|
|
% end
|
|
|
|
@transparent
|
|
static func _convertFromBuiltinIntegerLiteral(value: Builtin.Int${builtinIntLiteralBits}) -> ${Self} {
|
|
return ${Self}(Builtin.s_to_${sign}_checked_trunc_Int${builtinIntLiteralBits}_${BuiltinName}(value).0)
|
|
}
|
|
|
|
@transparent
|
|
static func convertFromIntegerLiteral(value: ${Self}) -> ${Self} {
|
|
return value
|
|
}
|
|
@transparent
|
|
func _getBuiltinArrayBoundValue() -> Builtin.Word {
|
|
% if bits < wordBits:
|
|
return Builtin.${ext}OrBitCast_${BuiltinName}_Word(self.value)
|
|
% elif bits > wordBits:
|
|
return Builtin.truncOrBitCast_${BuiltinName}_Word(self.value)
|
|
% elif BuiltinName == 'Word':
|
|
return self.value
|
|
% else:
|
|
return Builtin.${CastToWord}(self.value)
|
|
% end
|
|
}
|
|
|
|
typealias ArrayBoundType = ${Self}
|
|
func getArrayBoundValue() -> ${Self} {
|
|
return self
|
|
}
|
|
|
|
% if bits > 8:
|
|
/// Returns the big-endian representation of the integer, changing the
|
|
/// byte order if necessary.
|
|
var bigEndian: ${Self} {
|
|
#if arch(i386) || arch(x86_64) || arch(arm) || arch(arm64)
|
|
return ${Self}(Builtin.int_bswap_${BuiltinName}(value) )
|
|
#else
|
|
assert(false)
|
|
#endif
|
|
}
|
|
/// Returns the little-endian representation of the integer, changing the
|
|
/// byte order if necessary.
|
|
var littleEndian: ${Self} {
|
|
#if arch(i386) || arch(x86_64) || arch(arm) || arch(arm64)
|
|
return self
|
|
#else
|
|
assert(false)
|
|
#endif
|
|
}
|
|
% end
|
|
|
|
% if bits > 8:
|
|
/// Returns the current integer with the byte order swapped.
|
|
var byteSwapped: ${Self} {
|
|
return ${Self}(Builtin.int_bswap_${BuiltinName}(value))
|
|
}
|
|
% end
|
|
|
|
% max = maskBits((bits - 1) if signed else bits)
|
|
@transparent
|
|
static var max: ${Self} { return ${max} }
|
|
@transparent
|
|
static var min: ${Self} { return ${'-%s-1' % max if signed else '0'} }
|
|
}
|
|
|
|
extension ${Self} : Hashable {
|
|
var hashValue: Int {
|
|
% if bits < wordBits:
|
|
return Int(Builtin.sextOrBitCast_${BuiltinName}_Word(self.value))
|
|
% elif bits > wordBits:
|
|
var result: Int = 0
|
|
for var i = 0; i < (sizeofValue(self) * 8); i += sizeof(Int.self) * 8 {
|
|
result ^= Int(self >> ${Self}(i)) & ~0
|
|
}
|
|
return result
|
|
% elif BuiltinName == 'Word':
|
|
return Int(self.value)
|
|
% else:
|
|
return Int(Builtin.${CastToWord}(self.value))
|
|
% end
|
|
}
|
|
}
|
|
|
|
extension ${Self} : Printable {
|
|
var description: String {
|
|
% if signed:
|
|
return _int64ToString(self.toIntMax())
|
|
% else:
|
|
return _uint64ToString(self.toUIntMax())
|
|
% end
|
|
}
|
|
}
|
|
|
|
@transparent
|
|
extension ${Self} : RandomAccessIndex {
|
|
@transparent
|
|
func successor() -> ${Self} {
|
|
return self + 1
|
|
}
|
|
@transparent
|
|
func predecessor() -> ${Self} {
|
|
return self - 1
|
|
}
|
|
|
|
@transparent
|
|
func distanceTo(other: ${Self}) -> ${Self}.DistanceType {
|
|
return numericCast((numericCast(other) as IntMax) - numericCast(self))
|
|
}
|
|
|
|
@transparent
|
|
func advancedBy(amount: ${Self}.DistanceType) -> ${Self} {
|
|
return numericCast((numericCast(self) as IntMax) + numericCast(amount))
|
|
}
|
|
|
|
% for Method,op in [('Add', 'add'), ('Subtract', 'sub'), ('Multiply', 'mul')]:
|
|
@transparent
|
|
static func unchecked${Method}(lhs: ${Self}, _ rhs: ${Self}) -> (${Self}, 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'), ('Modulus', 'rem')]:
|
|
@transparent
|
|
static func unchecked${Method}(lhs: ${Self}, _ rhs: ${Self}) -> (${Self}, 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 = '' if signed else 'U'
|
|
@transparent
|
|
func to${U}IntMax() -> ${U}IntMax {
|
|
return ${'self' if Self == U+'Int%s'%maxBits else U+'IntMax(self)'}
|
|
}
|
|
% if not signed:
|
|
func toIntMax() -> IntMax {
|
|
return IntMax(toUIntMax())
|
|
}
|
|
% end
|
|
@transparent
|
|
static func from(x: ${U}IntMax) -> ${Self} {
|
|
return ${'x' if Self == U+'Int%s'%maxBits else Self+'(x)'}
|
|
}
|
|
}
|
|
|
|
% if signed:
|
|
@transparent
|
|
extension ${Self} : SignedNumber {}
|
|
% end
|
|
|
|
%# FIXME: checked conversions of Word types
|
|
// construction from other integer types
|
|
@transparent
|
|
extension ${Self} {
|
|
% for (srcName, srcBits, srcSigned) in allInts():
|
|
% Src = intName(srcName, srcSigned)
|
|
% srcBuiltinName = builtinIntName(srcName)
|
|
% (srcSign, srcExt) = ('s', 'sext') if srcSigned else ('u', 'zext')
|
|
% if Self != Src:
|
|
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
|
|
% end
|
|
func as${'Unsigned' if signed else 'Signed'}() -> ${OtherSelf} {
|
|
return ${OtherSelf}(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
|
|
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
|
|
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 @prefix
|
|
func ~(rhs: ${Self}) -> ${Self} {
|
|
let mask = ${Self}.uncheckedSubtract(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
|
|
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
|
|
func ${op} (lhs: ${Self}, rhs: ${Self}) -> ${Self} {
|
|
% if signed:
|
|
_precondition(U${Self}(rhs) < U${Self}(sizeofValue(rhs) * 8),
|
|
"shift amount is larger than type size in bits")
|
|
% else:
|
|
_precondition(rhs < ${Self}(sizeofValue(rhs) * 8),
|
|
"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
|
|
func ${op} (lhs: ${Self}, rhs: ${Self}) -> ${Self} {
|
|
return ${Self}(Builtin.${name}_${BuiltinName}(lhs.value, rhs.value))
|
|
}
|
|
% end
|
|
|
|
// bitwise operations
|
|
@transparent
|
|
extension ${Self} : BitwiseOperations {
|
|
static var allZeros: ${Self} { return 0 }
|
|
}
|
|
|
|
// Compound assignments
|
|
% for op in '+', '-', '*', '<<', '>>', '&', '|', '^':
|
|
@transparent @assignment
|
|
func ${op}=(inout lhs: ${Self}, rhs: ${Self}) {
|
|
lhs = lhs ${op} rhs
|
|
}
|
|
% end
|
|
% end # for bits in allInts
|
|
|
|
typealias Word = Int
|
|
typealias UWord = UInt
|
|
|
|
// ${'Local Variables'}:
|
|
// eval: (read-only-mode 1)
|
|
// End:
|