%# -*- 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) }% @public typealias IntMax = Int${maxBits} @public typealias UIntMax = UInt${maxBits} @public protocol _Integer : _BuiltinIntegerLiteralConvertible, IntegerLiteralConvertible, Printable, ArrayBound, Hashable, IntegerArithmetic, BitwiseOperations, _Incrementable { } @public protocol Integer : _Integer, RandomAccessIndex { } @public protocol _SignedInteger : _Integer, SignedNumber { func toIntMax() -> IntMax class func from(IntMax) -> Self } @public protocol SignedInteger : _SignedInteger, Integer { } @public protocol _UnsignedInteger : _Integer { func toUIntMax() -> UIntMax class func from(UIntMax) -> Self } @public protocol UnsignedInteger : _UnsignedInteger, Integer { } @public func numericCast(x: T) -> U { return .from(x.toIntMax()) } @public func numericCast(x: T) -> U { return .from(x.toUIntMax()) } @public func numericCast(x: T) -> U { return .from(UIntMax(x.toIntMax())) } @public func numericCast(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 '' @public struct ${Self} : ${'SignedInteger' if sign == 's' else 'UnsignedInteger'} { var value: Builtin.${BuiltinName} @transparent @public init() { var maxWidthZero: IntMax = 0 value = Builtin.truncOrBitCast_Int${maxBits}_${BuiltinName}(maxWidthZero.value) } @transparent init(_ v: Builtin.${BuiltinName}) { value = v } @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 assert(false) #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 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 @public 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 } @public typealias ArrayBoundType = ${Self} @public func getArrayBoundValue() -> ${Self} { return self } % 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 assert(false) #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 assert(false) #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'} } } extension ${Self} : Hashable { @public 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 { @public var description: String { % if signed: return _int64ToString(self.toIntMax()) % else: return _uint64ToString(self.toUIntMax()) % end } } @transparent extension ${Self} : RandomAccessIndex { @transparent @public func successor() -> ${Self} { return self + 1 } @transparent @public func predecessor() -> ${Self} { return self - 1 } @transparent @public func distanceTo(other: ${Self}) -> ${Self}.DistanceType { return numericCast((numericCast(other) as IntMax) - numericCast(self)) } @transparent @public 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 @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'), ('modulus', 'rem')]: /// Operations that return an overflow bit in addition to a partial result, /// helpful for checking for overflow when you want to handle it. @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: // 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 @public 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 @public 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: @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 % end @public 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 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: // 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 @public 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}(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 @public func ${op} (lhs: ${Self}, rhs: ${Self}) -> ${Self} { return ${Self}(Builtin.${name}_${BuiltinName}(lhs.value, rhs.value)) } % end // bitwise operations @transparent extension ${Self} : BitwiseOperations { @public static var allZeros: ${Self} { return 0 } } // Compound assignments % for op in '+', '-', '*', '<<', '>>', '&', '|', '^': @transparent @assignment @public func ${op}=(inout lhs: ${Self}, rhs: ${Self}) { lhs = lhs ${op} rhs } % end % end # for bits in allInts @public typealias Word = Int @public typealias UWord = UInt // ${'Local Variables'}: // eval: (read-only-mode 1) // End: