|
| 1 | +//===--- FunctionConvention.swift - function conventions ------------------===// |
| 2 | +// |
| 3 | +// This source file is part of the Swift.org open source project |
| 4 | +// |
| 5 | +// Copyright (c) 2014 - 2023 Apple Inc. and the Swift project authors |
| 6 | +// Licensed under Apache License v2.0 with Runtime Library Exception |
| 7 | +// |
| 8 | +// See https://swift.org/LICENSE.txt for license information |
| 9 | +// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors |
| 10 | +// |
| 11 | +//===----------------------------------------------------------------------===// |
| 12 | + |
| 13 | +import SILBridging |
| 14 | + |
| 15 | +/// SIL function convention based on the AST function type and SIL stage. |
| 16 | +public struct FunctionConvention { |
| 17 | + let bridgedFunctionType: BridgedASTType |
| 18 | + let hasLoweredAddresses: Bool |
| 19 | + |
| 20 | + init(for bridgedFunctionType: BridgedASTType, in function: Function) { |
| 21 | + self.bridgedFunctionType = bridgedFunctionType |
| 22 | + self.hasLoweredAddresses = function.hasLoweredAddresses |
| 23 | + } |
| 24 | + |
| 25 | + struct Results : Collection { |
| 26 | + let bridged: BridgedResultInfoArray |
| 27 | + let hasLoweredAddresses: Bool |
| 28 | + |
| 29 | + public var startIndex: Int { 0 } |
| 30 | + |
| 31 | + public var endIndex: Int { bridged.count() } |
| 32 | + |
| 33 | + public func index(after index: Int) -> Int { |
| 34 | + return index + 1 |
| 35 | + } |
| 36 | + |
| 37 | + public subscript(_ index: Int) -> ResultInfo { |
| 38 | + return ResultInfo(bridged: bridged.at(index), |
| 39 | + hasLoweredAddresses: hasLoweredAddresses) |
| 40 | + } |
| 41 | + } |
| 42 | + |
| 43 | + var results: Results { |
| 44 | + Results(bridged: bridgedFunctionType.SILFunctionType_getResults(), |
| 45 | + hasLoweredAddresses: hasLoweredAddresses) |
| 46 | + } |
| 47 | + |
| 48 | + /// Number of SIL arguments for indirect results, not including error results. |
| 49 | + var indirectSILResultCount: UInt { |
| 50 | + // TODO: Return packs directly in lowered-address mode |
| 51 | + return hasLoweredAddresses |
| 52 | + ? bridgedFunctionType.SILFunctionType_getNumIndirectFormalResults() |
| 53 | + : bridgedFunctionType.SILFunctionType_getNumPackResults() |
| 54 | + } |
| 55 | + |
| 56 | + var errorResult: ResultInfo? { |
| 57 | + guard bridgedFunctionType.SILFunctionType_hasErrorResult() else { |
| 58 | + return nil |
| 59 | + } |
| 60 | + return results[0] |
| 61 | + } |
| 62 | + |
| 63 | + /// The number of SIL error results passed as address-typed arguments. |
| 64 | + var indirectSILErrorResultCount: UInt { |
| 65 | + guard hasLoweredAddresses else { return 0 } |
| 66 | + return errorResult?.convention == .indirect ? 1 : 0 |
| 67 | + } |
| 68 | + |
| 69 | + var parameterCount: UInt { |
| 70 | + bridgedFunctionType.SILFunctionType_getNumParameters() |
| 71 | + } |
| 72 | + |
| 73 | + /// The SIL argument index of the function type's first parameter. |
| 74 | + var firstParameterIndex: UInt { |
| 75 | + indirectSILResultCount + indirectSILErrorResultCount |
| 76 | + } |
| 77 | + |
| 78 | + // The SIL argument index of the 'self' paramter. |
| 79 | + var selfIndex: UInt? { |
| 80 | + guard bridgedFunctionType.SILFunctionType_hasSelfParam() else { return nil } |
| 81 | + return firstParameterIndex + parameterCount - 1 |
| 82 | + } |
| 83 | +} |
| 84 | + |
| 85 | +/// A function result type and the rules for returning it in SIL. |
| 86 | +struct ResultInfo { |
| 87 | + /// The unsubstituted parameter type that describes the abstract calling convention of the parameter. |
| 88 | + /// |
| 89 | + /// TODO: For most purposes, you probably want \c returnValueType. |
| 90 | + let interfaceType: BridgedASTType |
| 91 | + let convention: ResultConvention |
| 92 | + let hasLoweredAddresses: Bool |
| 93 | + |
| 94 | + /// Is this result returned indirectly in SIL? Most formally indirect results can be returned directly in SIL. This depends on the calling function. |
| 95 | + var isSILIndirect: Bool { |
| 96 | + switch convention { |
| 97 | + case .indirect: |
| 98 | + return hasLoweredAddresses || interfaceType.isOpenedExistentialWithError() |
| 99 | + case .pack: |
| 100 | + return true |
| 101 | + case .owned, .unowned, .unownedInnerPointer, .autoreleased: |
| 102 | + return false |
| 103 | + } |
| 104 | + } |
| 105 | +} |
| 106 | + |
| 107 | +public enum ResultConvention { |
| 108 | + /// This result is returned indirectly, i.e. by passing the address of an uninitialized object in memory. The callee is responsible for leaving an initialized object at this address. The callee may assume that the address does not alias any valid object. |
| 109 | + case indirect |
| 110 | + |
| 111 | + /// The caller is responsible for destroying this return value. Its type is non-trivial. |
| 112 | + case owned |
| 113 | + |
| 114 | + /// The caller is not responsible for destroying this return value. Its type may be trivial, or it may simply be offered unsafely. It is valid at the instant of the return, but further operations may invalidate it. |
| 115 | + case unowned |
| 116 | + |
| 117 | + /// The caller is not responsible for destroying this return value. The validity of the return value is dependent on the 'self' parameter, so it may be invalidated if that parameter is released. |
| 118 | + case unownedInnerPointer |
| 119 | + |
| 120 | + /// This value has been (or may have been) returned autoreleased. The caller should make an effort to reclaim the autorelease. The type must be a class or class existential type, and this must be the only return value. |
| 121 | + case autoreleased |
| 122 | + |
| 123 | + /// This value is a pack that is returned indirectly by passing a pack address (which may or may not be further indirected, depending on the pact type). The callee is responsible for leaving an initialized object in each element of the pack. |
| 124 | + case pack |
| 125 | + |
| 126 | + /// Does this result convention require indirect storage? This reflects a FunctionType's conventions, as opposed to the SIL conventions that dictate SILValue types. |
| 127 | + public var isASTIndirect: Bool { |
| 128 | + switch self { |
| 129 | + case .indirect, .pack: |
| 130 | + return true |
| 131 | + default: |
| 132 | + return false |
| 133 | + } |
| 134 | + } |
| 135 | + public var isASTDirect: Bool { |
| 136 | + return !isASTIndirect |
| 137 | + } |
| 138 | +} |
| 139 | + |
| 140 | +// Bridging utilities |
| 141 | + |
| 142 | +extension ResultInfo { |
| 143 | + init(bridged: BridgedResultInfo, hasLoweredAddresses: Bool) { |
| 144 | + self.interfaceType = BridgedASTType(type: bridged.type) |
| 145 | + self.convention = ResultConvention(bridged: bridged.convention) |
| 146 | + self.hasLoweredAddresses = hasLoweredAddresses |
| 147 | + } |
| 148 | +} |
| 149 | + |
| 150 | +extension ResultConvention { |
| 151 | + init(bridged: BridgedResultConvention) { |
| 152 | + switch bridged { |
| 153 | + case .Indirect: self = .indirect |
| 154 | + case .Owned: self = .owned |
| 155 | + case .Unowned: self = .unowned |
| 156 | + case .UnownedInnerPointer: self = .unownedInnerPointer |
| 157 | + case .Autoreleased: self = .autoreleased |
| 158 | + case .Pack: self = .pack |
| 159 | + default: |
| 160 | + fatalError("unsupported result convention") |
| 161 | + } |
| 162 | + } |
| 163 | +} |
0 commit comments