mirror of
https://github.com/apple/swift.git
synced 2025-12-14 20:36:38 +01:00
414 lines
11 KiB
Swift
414 lines
11 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 }
|
|
|
|
@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
|
|
}
|
|
|
|
% 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 succ() -> ${Self} {
|
|
return self + 1
|
|
}
|
|
@transparent
|
|
func pred() -> ${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:
|
|
assert(U${Self}(rhs) < U${Self}(sizeofValue(rhs) * 8))
|
|
% else:
|
|
assert(rhs < ${Self}(sizeofValue(rhs) * 8))
|
|
% 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:
|