Skip to content

Commit 4a60ea8

Browse files
committed
Add some Swift SIL infrastructure
* In `ApplySite`: `argumentOperands` and `isCalleeOperand` * In `ArgumentConvention`: `isIndirect`, `isIndirectIn` and `isGuaranteed` * In `Function`: `isDefinition`, `numParameterArguments`, `numArguments`, `getArgumentConvention`, `effectAttribute` * In `Type`: `isFunction` and `isCalleeConsumedFunction` * In `Instruction`: `hasUnspecifiedSideEffects` * New bridged instructions: `EndApplyInst` and `AbortApplyInst` * `LoadInst.ownership` * `BeginAccessInst.isStatic` * make the `Allocation` protocol a `SingleValueInstruction` (instead of `AnyObject`)
1 parent 8720139 commit 4a60ea8

File tree

8 files changed

+244
-5
lines changed

8 files changed

+244
-5
lines changed

SwiftCompilerSources/Sources/SIL/ApplySite.swift

Lines changed: 21 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -67,17 +67,30 @@ public protocol ApplySite : Instruction {
6767
extension ApplySite {
6868
public var callee: Value { operands[ApplyOperands.calleeOperandIndex].value }
6969

70-
public var arguments: LazyMapSequence<OperandArray, Value> {
70+
/// Returns the subset of operands which are argument operands.
71+
///
72+
/// This does not include the callee function operand.
73+
public var argumentOperands: OperandArray {
7174
let numArgs = ApplySite_getNumArguments(bridged)
7275
let offset = ApplyOperands.firstArgumentIndex
73-
let argOps = operands[offset..<(numArgs + offset)]
74-
return argOps.lazy.map { $0.value }
76+
return operands[offset..<(numArgs + offset)]
77+
}
78+
79+
/// Returns the subset of operand values which are arguments.
80+
///
81+
/// This does not include the callee function operand.
82+
public var arguments: LazyMapSequence<OperandArray, Value> {
83+
argumentOperands.lazy.map { $0.value }
7584
}
7685

7786
public var substitutionMap: SubstitutionMap {
7887
SubstitutionMap(ApplySite_getSubstitutionMap(bridged))
7988
}
8089

90+
/// Returns the argument index of an operand.
91+
///
92+
/// Returns nil if 'operand' is not an argument operand. This is the case if
93+
/// it's the callee function operand.
8194
public func argumentIndex(of operand: Operand) -> Int? {
8295
let opIdx = operand.index
8396
if opIdx >= ApplyOperands.firstArgumentIndex &&
@@ -87,6 +100,11 @@ extension ApplySite {
87100
return nil
88101
}
89102

103+
/// Returns true if `operand` is the callee function operand and not am argument operand.
104+
public func isCalleeOperand(_ operand: Operand) -> Bool {
105+
return operand.index < ApplyOperands.firstArgumentIndex
106+
}
107+
90108
public func getArgumentConvention(calleeArgIndex: Int) -> ArgumentConvention {
91109
return ApplySite_getArgumentConvention(bridged, calleeArgIndex).convention
92110
}

SwiftCompilerSources/Sources/SIL/Argument.swift

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -128,6 +128,36 @@ public enum ArgumentConvention {
128128
/// guarantees its validity for the entirety of the call.
129129
case directGuaranteed
130130

131+
public var isIndirect: Bool {
132+
switch self {
133+
case .indirectIn, .indirectInConstant, .indirectInGuaranteed,
134+
.indirectInout, .indirectInoutAliasable, .indirectOut:
135+
return true
136+
case .directOwned, .directUnowned, .directGuaranteed:
137+
return false
138+
}
139+
}
140+
141+
public var isIndirectIn: Bool {
142+
switch self {
143+
case .indirectIn, .indirectInConstant, .indirectInGuaranteed:
144+
return true
145+
case .directOwned, .directUnowned, .directGuaranteed,
146+
.indirectInout, .indirectInoutAliasable, .indirectOut:
147+
return false
148+
}
149+
}
150+
151+
public var isGuaranteed: Bool {
152+
switch self {
153+
case .indirectInGuaranteed, .directGuaranteed:
154+
return true
155+
case .indirectIn, .indirectInConstant, .directOwned, .directUnowned,
156+
.indirectInout, .indirectInoutAliasable, .indirectOut:
157+
return false
158+
}
159+
}
160+
131161
public var isExclusiveIndirect: Bool {
132162
switch self {
133163
case .indirectIn,

SwiftCompilerSources/Sources/SIL/Function.swift

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

3434
public var hasOwnership: Bool { SILFunction_hasOwnership(bridged) != 0 }
3535

36+
/// Returns true if the function is a definition and not only an external declaration.
37+
///
38+
/// This is the case if the functioun contains a body, i.e. some basic blocks.
39+
public var isDefinition: Bool { blocks.first != nil }
40+
3641
public var entryBlock: BasicBlock {
3742
SILFunction_firstBlock(bridged).block!
3843
}
@@ -50,9 +55,22 @@ final public class Function : CustomStringConvertible, HasShortDescription, Hash
5055
blocks.lazy.flatMap { $0.instructions }
5156
}
5257

58+
/// The number of indirect result arguments.
5359
public var numIndirectResultArguments: Int {
5460
SILFunction_numIndirectResultArguments(bridged)
5561
}
62+
63+
/// The number of arguments which correspond to parameters (and not to indirect results).
64+
public var numParameterArguments: Int {
65+
SILFunction_numParameterArguments(bridged)
66+
}
67+
68+
/// The total number of arguments.
69+
///
70+
/// This is the sum of indirect result arguments and parameter arguments.
71+
/// If the function is a definition (i.e. it has at least an entry block), this is the
72+
/// number of arguments of the function's entry block.
73+
public var numArguments: Int { numIndirectResultArguments + numParameterArguments }
5674

5775
public var hasSelfArgument: Bool {
5876
SILFunction_getSelfArgumentIndex(bridged) >= 0
@@ -67,6 +85,13 @@ final public class Function : CustomStringConvertible, HasShortDescription, Hash
6785
public var argumentTypes: ArgumentTypeArray { ArgumentTypeArray(function: self) }
6886
public var resultType: Type { SILFunction_getSILResultType(bridged).type }
6987

88+
public func getArgumentConvention(for argumentIndex: Int) -> ArgumentConvention {
89+
if argumentIndex < numIndirectResultArguments {
90+
return .indirectOut
91+
}
92+
return SILFunction_getSILArgumentConvention(bridged, argumentIndex).convention
93+
}
94+
7095
public var returnInstruction: ReturnInst? {
7196
for block in blocks.reversed() {
7297
if let retInst = block.terminator as? ReturnInst { return retInst }
@@ -96,6 +121,60 @@ final public class Function : CustomStringConvertible, HasShortDescription, Hash
96121
}
97122
}
98123

124+
/// Kinds of effect attributes which can be defined for a Swift function.
125+
public enum EffectAttribute {
126+
/// No effect attribute is specified.
127+
case none
128+
129+
/// `[readnone]`
130+
///
131+
/// A readnone function does not have any observable memory read or write operations.
132+
/// This does not mean that the function cannot read or write at all. For example,
133+
/// it’s allowed to allocate and write to local objects inside the function.
134+
///
135+
/// A function can be marked as readnone if two calls of the same function with the
136+
/// same parameters can be simplified to one call (e.g. by the CSE optimization).
137+
/// Some conclusions:
138+
/// * A readnone function must not return a newly allocated class instance.
139+
/// * A readnone function can return a newly allocated copy-on-write object,
140+
/// like an Array, because COW data types conceptually behave like value types.
141+
/// * A readnone function must not release any parameter or any object indirectly
142+
/// referenced from a parameter.
143+
/// * Any kind of observable side-effects are not allowed, like `print`, file IO, etc.
144+
case readNone
145+
146+
/// `[readonly]`
147+
///
148+
/// A readonly function does not have any observable memory write operations.
149+
/// Similar to readnone, a readonly function is allowed to contain writes to e.g. local objects, etc.
150+
///
151+
/// A function can be marked as readonly if it’s save to eliminate a call to such
152+
/// a function if its return value is not used.
153+
/// The same conclusions as for readnone also apply to readonly.
154+
case readOnly
155+
156+
/// `[releasenone]`
157+
///
158+
/// A releasenone function must not perform any observable release-operation on an object.
159+
/// This means, it must not do anything which might let the caller observe any decrement of
160+
/// a reference count or any deallocations.
161+
/// Note that it's allowed to release an object if the release is balancing a retain in the
162+
/// same function. Also, it's allowed to release (and deallocate) local objects which were
163+
/// allocated in the same function.
164+
case releaseNone
165+
}
166+
167+
/// The effect attribute which is specified in the source code (if any).
168+
public var effectAttribute: EffectAttribute {
169+
switch SILFunction_getEffectAttribute(bridged) {
170+
case EffectKind_none: return .none
171+
case EffectKind_readNone: return .readNone
172+
case EffectKind_readOnly: return .readOnly
173+
case EffectKind_releaseNone: return .releaseNone
174+
default: fatalError()
175+
}
176+
}
177+
99178
/// True, if the function runs with a swift 5.1 runtime.
100179
/// Note that this is function specific, because inlinable functions are de-serialized
101180
/// in a client module, which might be compiled with a different deployment target.

SwiftCompilerSources/Sources/SIL/Instruction.swift

Lines changed: 26 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -104,6 +104,10 @@ public class Instruction : ListNode, CustomStringConvertible, Hashable {
104104
return SILInstruction_mayRelease(bridged)
105105
}
106106

107+
public final var hasUnspecifiedSideEffects: Bool {
108+
return SILInstruction_hasUnspecifiedSideEffects(bridged)
109+
}
110+
107111
public func visitReferencedFunctions(_ cl: (Function) -> ()) {
108112
}
109113

@@ -273,6 +277,9 @@ final public class UnconditionalCheckedCastAddrInst : Instruction {
273277
public override var mayTrap: Bool { true }
274278
}
275279

280+
final public class EndApplyInst : Instruction, UnaryInstruction {}
281+
final public class AbortApplyInst : Instruction, UnaryInstruction {}
282+
276283
final public class SetDeallocatingInst : Instruction, UnaryInstruction {}
277284

278285
final public class DeallocRefInst : Instruction, UnaryInstruction {}
@@ -312,7 +319,15 @@ final public class UnimplementedRefCountingInst : RefCountingInst {}
312319
final public class UnimplementedSingleValueInst : SingleValueInstruction {
313320
}
314321

315-
final public class LoadInst : SingleValueInstruction, UnaryInstruction {}
322+
final public class LoadInst : SingleValueInstruction, UnaryInstruction {
323+
// must match with enum class LoadOwnershipQualifier
324+
public enum LoadOwnership: Int {
325+
case unqualified = 0, take = 1, copy = 2, trivial = 3
326+
}
327+
public var ownership: LoadOwnership {
328+
LoadOwnership(rawValue: LoadInst_getLoadOwnership(bridged))!
329+
}
330+
}
316331

317332
final public class LoadWeakInst : SingleValueInstruction, UnaryInstruction {}
318333
final public class LoadUnownedInst : SingleValueInstruction, UnaryInstruction {}
@@ -570,11 +585,20 @@ extension BridgedAccessKind {
570585
// TODO: add support for begin_unpaired_access
571586
final public class BeginAccessInst : SingleValueInstruction, UnaryInstruction {
572587
public var accessKind: AccessKind { BeginAccessInst_getAccessKind(bridged).kind }
588+
589+
public var isStatic: Bool { BeginAccessInst_isStatic(bridged) != 0 }
573590
}
574591

592+
// An instruction that is always paired with a scope ending instruction
593+
// such as `begin_access` (ending with `end_access`) and `alloc_stack`
594+
// (ending with `dealloc_stack`).
575595
public protocol ScopedInstruction {
596+
// The type of the ending instructions (while `IteratorProtocol` would be
597+
// ideal, for performance reasons we allow the user to specify any type as return)
576598
associatedtype EndInstructions
577599

600+
// The instructions that end the scope of the instruction denoted
601+
// by `self`.
578602
var endInstructions: EndInstructions { get }
579603
}
580604

@@ -646,7 +670,7 @@ class MarkMustCheckInst : SingleValueInstruction, UnaryInstruction {}
646670
// single-value allocation instructions
647671
//===----------------------------------------------------------------------===//
648672

649-
public protocol Allocation : AnyObject { }
673+
public protocol Allocation : SingleValueInstruction { }
650674

651675
final public class AllocStackInst : SingleValueInstruction, Allocation {
652676
}

SwiftCompilerSources/Sources/SIL/Registration.swift

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,8 @@ public func registerSILClasses() {
5151
register(DebugValueInst.self)
5252
register(UnconditionalCheckedCastAddrInst.self)
5353
register(SetDeallocatingInst.self)
54+
register(EndApplyInst.self)
55+
register(AbortApplyInst.self)
5456
register(DeallocRefInst.self)
5557
register(StrongRetainInst.self)
5658
register(RetainValueInst.self)

SwiftCompilerSources/Sources/SIL/Type.swift

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,13 +36,16 @@ public struct Type : CustomStringConvertible, NoReflectionChildren {
3636
public var isStruct: Bool { SILType_isStruct(bridged) != 0 }
3737
public var isTuple: Bool { SILType_isTuple(bridged) != 0 }
3838
public var isEnum: Bool { SILType_isEnum(bridged) != 0 }
39+
public var isFunction: Bool { SILType_isFunction(bridged) }
3940

4041
public var tupleElements: TupleElementArray { TupleElementArray(type: self) }
4142

4243
public func getNominalFields(in function: Function) -> NominalFieldsArray {
4344
NominalFieldsArray(type: self, function: function)
4445
}
4546

47+
public var isCalleeConsumedFunction: Bool { SILType_isCalleeConsumedFunction(bridged) }
48+
4649
public func getIndexOfEnumCase(withName name: String) -> Int? {
4750
let idx = name._withStringRef {
4851
SILType_getCaseIdxOfEnumType(bridged, $0)

include/swift/SIL/SILBridging.h

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -175,6 +175,13 @@ typedef enum {
175175
MayHaveSideEffectsBehavior
176176
} BridgedMemoryBehavior;
177177

178+
typedef enum {
179+
EffectKind_none,
180+
EffectKind_readNone,
181+
EffectKind_readOnly,
182+
EffectKind_releaseNone,
183+
} BridgedEffectAttributeKind;
184+
178185
typedef enum {
179186
AccessKind_Init,
180187
AccessKind_Read,
@@ -249,15 +256,18 @@ SwiftInt SILFunction_hasOwnership(BridgedFunction function);
249256
OptionalBridgedBasicBlock SILFunction_firstBlock(BridgedFunction function);
250257
OptionalBridgedBasicBlock SILFunction_lastBlock(BridgedFunction function);
251258
SwiftInt SILFunction_numIndirectResultArguments(BridgedFunction function);
259+
SwiftInt SILFunction_numParameterArguments(BridgedFunction function);
252260
SwiftInt SILFunction_getSelfArgumentIndex(BridgedFunction function);
253261
SwiftInt SILFunction_getNumSILArguments(BridgedFunction function);
254262
BridgedType SILFunction_getSILArgumentType(BridgedFunction function, SwiftInt idx);
263+
BridgedArgumentConvention SILFunction_getSILArgumentConvention(BridgedFunction function, SwiftInt idx);
255264
BridgedType SILFunction_getSILResultType(BridgedFunction function);
256265
SwiftInt SILFunction_isSwift51RuntimeAvailable(BridgedFunction function);
257266
SwiftInt SILFunction_isPossiblyUsedExternally(BridgedFunction function);
258267
SwiftInt SILFunction_isAvailableExternally(BridgedFunction function);
259268
SwiftInt SILFunction_hasSemanticsAttr(BridgedFunction function,
260269
llvm::StringRef attrName);
270+
BridgedEffectAttributeKind SILFunction_getEffectAttribute(BridgedFunction function);
261271
SwiftInt SILFunction_needsStackProtection(BridgedFunction function);
262272
void SILFunction_setNeedStackProtection(BridgedFunction function,
263273
SwiftInt needSP);
@@ -316,6 +326,8 @@ SwiftInt SILType_isClass(BridgedType type);
316326
SwiftInt SILType_isStruct(BridgedType type);
317327
SwiftInt SILType_isTuple(BridgedType type);
318328
SwiftInt SILType_isEnum(BridgedType type);
329+
bool SILType_isFunction(BridgedType type);
330+
bool SILType_isCalleeConsumedFunction(BridgedType type);
319331
SwiftInt SILType_getNumTupleElements(BridgedType type);
320332
BridgedType SILType_getTupleElementType(BridgedType type, SwiftInt elementIdx);
321333
SwiftInt SILType_getNumNominalFields(BridgedType type);
@@ -342,6 +354,7 @@ void SILInstruction_setOperand(BridgedInstruction inst, SwiftInt index,
342354
swift::SILDebugLocation SILInstruction_getLocation(BridgedInstruction inst);
343355
BridgedMemoryBehavior SILInstruction_getMemBehavior(BridgedInstruction inst);
344356
bool SILInstruction_mayRelease(BridgedInstruction inst);
357+
bool SILInstruction_hasUnspecifiedSideEffects(BridgedInstruction inst);
345358

346359
BridgedInstruction MultiValueInstResult_getParent(BridgedMultiValueResult result);
347360
SwiftInt MultiValueInstResult_getIndex(BridgedMultiValueResult result);
@@ -352,6 +365,7 @@ BridgedMultiValueResult
352365
BridgedArrayRef TermInst_getSuccessors(BridgedInstruction term);
353366

354367
llvm::StringRef CondFailInst_getMessage(BridgedInstruction cfi);
368+
SwiftInt LoadInst_getLoadOwnership(BridgedInstruction load);
355369
BridgedBuiltinID BuiltinInst_getID(BridgedInstruction bi);
356370
SwiftInt AddressToPointerInst_needsStackProtection(BridgedInstruction atp);
357371
SwiftInt IndexAddrInst_needsStackProtection(BridgedInstruction ia);
@@ -384,6 +398,7 @@ SwiftInt SwitchEnumInst_getNumCases(BridgedInstruction se);
384398
SwiftInt SwitchEnumInst_getCaseIndex(BridgedInstruction se, SwiftInt idx);
385399
SwiftInt StoreInst_getStoreOwnership(BridgedInstruction store);
386400
BridgedAccessKind BeginAccessInst_getAccessKind(BridgedInstruction beginAccess);
401+
SwiftInt BeginAccessInst_isStatic(BridgedInstruction beginAccess);
387402
SwiftInt CopyAddrInst_isTakeOfSrc(BridgedInstruction copyAddr);
388403
SwiftInt CopyAddrInst_isInitializationOfDest(BridgedInstruction copyAddr);
389404
void RefCountingInst_setIsAtomic(BridgedInstruction rc, bool isAtomic);

0 commit comments

Comments
 (0)