Skip to content

Commit c1f0f06

Browse files
committed
[SIL] Add FunctionConvention.swift
Bridge information about the AST function type that does not require a SIL function body. Support querying the function type's ResultInfo.
1 parent 7a18dd4 commit c1f0f06

File tree

7 files changed

+312
-1
lines changed

7 files changed

+312
-1
lines changed

SwiftCompilerSources/Sources/Optimizer/Utilities/OptUtils.swift

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
//===--- OptUtils.swift - Utilities for optimizations ----------------------===//
1+
//===--- OptUtils.swift - Utilities for optimizations ---------------------===//
22
//
33
// This source file is part of the Swift.org open source project
44
//
@@ -10,6 +10,7 @@
1010
//
1111
//===----------------------------------------------------------------------===//
1212

13+
import ASTBridging
1314
import SIL
1415
import OptimizerBridging
1516

SwiftCompilerSources/Sources/SIL/ApplySite.swift

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -120,6 +120,12 @@ extension ApplySite {
120120
return nil
121121
}
122122

123+
/// Get the conventions of the callee without the applied substitutions.
124+
public var originalCalleeConvention: FunctionConvention {
125+
FunctionConvention(for: callee.type.bridged.getASTType(),
126+
in: parentFunction)
127+
}
128+
123129
public func hasSemanticsAttribute(_ attr: StaticString) -> Bool {
124130
if let callee = referencedFunction {
125131
return callee.hasSemanticsAttribute(attr)

SwiftCompilerSources/Sources/SIL/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ add_swift_compiler_module(SIL
1717
Effects.swift
1818
ForwardingInstruction.swift
1919
Function.swift
20+
FunctionConvention.swift
2021
GlobalVariable.swift
2122
Instruction.swift
2223
Location.swift

SwiftCompilerSources/Sources/SIL/Function.swift

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,8 @@ final public class Function : CustomStringConvertible, HasShortDescription, Hash
3333

3434
public var hasOwnership: Bool { bridged.hasOwnership() }
3535

36+
public var hasLoweredAddresses: Bool { bridged.hasLoweredAddresses() }
37+
3638
/// Returns true if the function is a definition and not only an external declaration.
3739
///
3840
/// This is the case if the functioun contains a body, i.e. some basic blocks.
Lines changed: 163 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,163 @@
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+
}

include/swift/SIL/SILBridging.h

Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -60,13 +60,87 @@ class SILWitnessTable;
6060
class SILDefaultWitnessTable;
6161
class NominalTypeDecl;
6262
class VarDecl;
63+
class TypeBase;
6364
class SwiftPassInvocation;
6465
class GenericSpecializationInformation;
6566
}
6667

6768
bool swiftModulesInitialized();
6869
void registerBridgedClass(BridgedStringRef className, SwiftMetatype metatype);
6970

71+
enum class BridgedResultConvention {
72+
Indirect,
73+
Owned,
74+
Unowned,
75+
UnownedInnerPointer,
76+
Autoreleased,
77+
Pack
78+
};
79+
80+
// A null type indicates a non-existant result, in which case `convention` is undefined.
81+
struct BridgedResultInfo {
82+
swift::TypeBase * _Nonnull type;
83+
BridgedResultConvention convention;
84+
85+
#ifdef USED_IN_CPP_SOURCE
86+
inline static BridgedResultConvention
87+
castToResultConvention(swift::ResultConvention convention);
88+
89+
BridgedResultInfo(swift::SILResultInfo resultInfo):
90+
type(resultInfo.getInterfaceType().getPointer()),
91+
convention(castToResultConvention(resultInfo.getConvention()))
92+
{}
93+
#endif
94+
};
95+
96+
struct BridgedResultInfoArray {
97+
BridgedArrayRef resultInfoArray;
98+
99+
#ifdef USED_IN_CPP_SOURCE
100+
BridgedResultInfoArray(llvm::ArrayRef<swift::SILResultInfo> results)
101+
: resultInfoArray(results) {}
102+
103+
llvm::ArrayRef<swift::SILResultInfo> unbridged() const {
104+
return resultInfoArray.unbridged<swift::SILResultInfo>();
105+
}
106+
#endif
107+
108+
BRIDGED_INLINE SwiftInt count() const;
109+
110+
SWIFT_IMPORT_UNSAFE BRIDGED_INLINE
111+
BridgedResultInfo at(SwiftInt argumentIndex) const;
112+
};
113+
114+
// Temporary access to the AST type within SIL until ASTBridging provides it.
115+
struct BridgedASTType {
116+
swift::TypeBase * _Nullable type;
117+
118+
#ifdef USED_IN_CPP_SOURCE
119+
swift::Type unbridged() const {
120+
return type;
121+
}
122+
#endif
123+
124+
BRIDGED_INLINE bool isOpenedExistentialWithError() const;
125+
126+
// =========================================================================//
127+
// SILFunctionType
128+
// =========================================================================//
129+
130+
SWIFT_IMPORT_UNSAFE BRIDGED_INLINE
131+
BridgedResultInfoArray SILFunctionType_getResults() const;
132+
133+
BRIDGED_INLINE SwiftUInt SILFunctionType_getNumIndirectFormalResults() const;
134+
135+
BRIDGED_INLINE SwiftUInt SILFunctionType_getNumPackResults() const;
136+
137+
BRIDGED_INLINE bool SILFunctionType_hasErrorResult() const;
138+
139+
BRIDGED_INLINE SwiftUInt SILFunctionType_getNumParameters() const;
140+
141+
BRIDGED_INLINE bool SILFunctionType_hasSelfParam() const;
142+
};
143+
70144
struct BridgedType {
71145
void * _Nullable opaqueValue;
72146

@@ -111,6 +185,7 @@ struct BridgedType {
111185
BRIDGED_INLINE bool isAddress() const;
112186
SWIFT_IMPORT_UNSAFE BRIDGED_INLINE BridgedType getAddressType() const;
113187
SWIFT_IMPORT_UNSAFE BRIDGED_INLINE BridgedType getObjectType() const;
188+
SWIFT_IMPORT_UNSAFE BRIDGED_INLINE BridgedASTType getASTType() const;
114189
BRIDGED_INLINE bool isTrivial(BridgedFunction f) const;
115190
BRIDGED_INLINE bool isNonTrivialOrContainsRawPointer(BridgedFunction f) const;
116191
BRIDGED_INLINE bool isValueTypeWithDeinit() const;
@@ -318,6 +393,7 @@ struct BridgedFunction {
318393
SWIFT_IMPORT_UNSAFE BRIDGED_INLINE BridgedStringRef getName() const;
319394
SWIFT_IMPORT_UNSAFE BridgedOwnedString getDebugDescription() const;
320395
BRIDGED_INLINE bool hasOwnership() const;
396+
BRIDGED_INLINE bool hasLoweredAddresses() const;
321397
SWIFT_IMPORT_UNSAFE BRIDGED_INLINE OptionalBridgedBasicBlock getFirstBlock() const;
322398
SWIFT_IMPORT_UNSAFE BRIDGED_INLINE OptionalBridgedBasicBlock getLastBlock() const;
323399
BRIDGED_INLINE SwiftInt getNumIndirectFormalResults() const;
@@ -347,6 +423,7 @@ struct BridgedFunction {
347423
BRIDGED_INLINE bool needsStackProtection() const;
348424
BRIDGED_INLINE void setNeedStackProtection(bool needSP) const;
349425
BRIDGED_INLINE bool isResilientNominalDecl(BridgedNominalTypeDecl decl) const;
426+
BRIDGED_INLINE BridgedType getLoweredType(BridgedASTType type) const;
350427

351428
enum class ParseEffectsMode {
352429
argumentEffectsFromSource,

0 commit comments

Comments
 (0)