mirror of
https://github.com/apple/swift.git
synced 2025-12-21 12:14:44 +01:00
Swift SIL: escape effects for function arguments.
Store a list of argument effects in a function, which specify if and how arguments escape. Such effects can be specified in the Swift source code (for details see docs/ReferenceGuides/UnderscoredAttributes.md) or derived in an optimization pass. For details see the documentation in SwiftCompilerSources/Sources/SIL/Effects.swift.
This commit is contained in:
@@ -13,6 +13,7 @@
|
||||
import SILBridging
|
||||
|
||||
final public class Function : CustomStringConvertible, HasName {
|
||||
public private(set) var effects = FunctionEffects()
|
||||
|
||||
public var name: String {
|
||||
return SILFunction_getName(bridged).string
|
||||
@@ -51,6 +52,96 @@ final public class Function : CustomStringConvertible, HasName {
|
||||
public var argumentTypes: ArgumentTypeArray { ArgumentTypeArray(function: self) }
|
||||
public var resultType: Type { SILFunction_getSILResultType(bridged).type }
|
||||
|
||||
// Only to be called by PassContext
|
||||
public func _modifyEffects(_ body: (inout FunctionEffects) -> ()) {
|
||||
body(&effects)
|
||||
}
|
||||
|
||||
static func register() {
|
||||
func checkLayout(_ p: UnsafeMutablePointer<FunctionEffects>,
|
||||
data: UnsafeMutableRawPointer, size: Int) {
|
||||
assert(MemoryLayout<FunctionEffects>.size <= size, "wrong FunctionInfo size")
|
||||
assert(UnsafeMutableRawPointer(p) == data, "wrong FunctionInfo layout")
|
||||
}
|
||||
|
||||
let metatype = unsafeBitCast(Function.self, to: SwiftMetatype.self)
|
||||
Function_register(metatype,
|
||||
// initFn
|
||||
{ (f: BridgedFunction, data: UnsafeMutableRawPointer, size: Int) in
|
||||
checkLayout(&f.function.effects, data: data, size: size)
|
||||
data.initializeMemory(as: FunctionEffects.self, repeating: FunctionEffects(), count: 1)
|
||||
},
|
||||
// destroyFn
|
||||
{ (f: BridgedFunction, data: UnsafeMutableRawPointer, size: Int) in
|
||||
checkLayout(&f.function.effects, data: data, size: size)
|
||||
data.assumingMemoryBound(to: FunctionEffects.self).deinitialize(count: 1)
|
||||
},
|
||||
// writeFn
|
||||
{ (f: BridgedFunction, os: BridgedOStream, idx: Int) in
|
||||
let s = f.function.effects.argumentEffects[idx].description
|
||||
s.withBridgedStringRef { OStream_write(os, $0) }
|
||||
},
|
||||
// parseFn:
|
||||
{ (f: BridgedFunction, str: BridgedStringRef, fromSIL: Int, isDerived: Int, paramNames: BridgedArrayRef) -> BridgedParsingError in
|
||||
do {
|
||||
var parser = StringParser(str.string)
|
||||
let effect: ArgumentEffect
|
||||
if fromSIL != 0 {
|
||||
effect = try parser.parseEffectFromSIL(for: f.function, isDerived: isDerived != 0)
|
||||
} else {
|
||||
let paramToIdx = paramNames.withElements(ofType: BridgedStringRef.self) {
|
||||
(buffer: UnsafeBufferPointer<BridgedStringRef>) -> Dictionary<String, Int> in
|
||||
let keyValPairs = buffer.enumerated().lazy.map { ($0.1.string, $0.0) }
|
||||
return Dictionary(uniqueKeysWithValues: keyValPairs)
|
||||
}
|
||||
effect = try parser.parseEffectFromSource(for: f.function, params: paramToIdx)
|
||||
}
|
||||
if !parser.isEmpty() { try parser.throwError("syntax error") }
|
||||
|
||||
f.function.effects.argumentEffects.append(effect)
|
||||
} catch let error as ParsingError {
|
||||
return BridgedParsingError(message: error.message.utf8Start, position: error.position)
|
||||
} catch {
|
||||
fatalError()
|
||||
}
|
||||
return BridgedParsingError(message: nil, position: 0)
|
||||
},
|
||||
// copyEffectsFn
|
||||
{ (toFunc: BridgedFunction, fromFunc: BridgedFunction) -> Int in
|
||||
let srcFunc = fromFunc.function
|
||||
let destFunc = toFunc.function
|
||||
let srcResultArgs = srcFunc.numIndirectResultArguments
|
||||
let destResultArgs = destFunc.numIndirectResultArguments
|
||||
|
||||
// We only support reabstraction (indirect -> direct) of a single
|
||||
// return value.
|
||||
if srcResultArgs != destResultArgs &&
|
||||
(srcResultArgs > 1 || destResultArgs > 1) {
|
||||
return 0
|
||||
}
|
||||
destFunc.effects =
|
||||
FunctionEffects(copiedFrom: srcFunc.effects,
|
||||
resultArgDelta: destResultArgs - srcResultArgs)
|
||||
return 1
|
||||
},
|
||||
// getEffectFlags
|
||||
{ (f: BridgedFunction, idx: Int) -> Int in
|
||||
let argEffects = f.function.effects.argumentEffects
|
||||
if idx >= argEffects.count { return 0 }
|
||||
let effect = argEffects[idx]
|
||||
var flags = 0
|
||||
switch effect.kind {
|
||||
case .notEscaping, .escaping:
|
||||
flags |= Int(EffectsFlagEscape)
|
||||
}
|
||||
if effect.isDerived {
|
||||
flags |= Int(EffectsFlagDerived)
|
||||
}
|
||||
return flags
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
public var bridged: BridgedFunction { BridgedFunction(obj: SwiftObject(self)) }
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user