mirror of
https://github.com/apple/swift.git
synced 2025-12-14 20:36:38 +01:00
For chains of async functions where suspensions can be statically
proven to never be required, this pass removes all suspensions and
turns the functions into synchronous functions.
For example, this function does not actually require any suspensions,
once the correct executor is acquired upon initial entry:
```
func fib(_ n: Int) async -> Int {
if n <= 1 { return n }
return await fib(n-1) + fib(n-2)
}
```
So we can turn the above into this for better performance:
```
func fib() async -> Int {
return fib_sync()
}
func fib_sync(_ n: Int) -> Int {
if n <= 1 { return n }
return fib(n-1) + fib(n-2)
}
```
while rewriting callers of `fib` to use the `sync` entry-point
when we can prove that it will be invoked on a compatible executor.
This pass is currently experimental and under development. Thus, it
is disabled by default and you must use
`-enable-experimental-async-demotion` to try it.
138 lines
4.4 KiB
Swift
138 lines
4.4 KiB
Swift
//===--- ModulePassContext.swift ------------------------------------------===//
|
|
//
|
|
// This source file is part of the Swift.org open source project
|
|
//
|
|
// Copyright (c) 2014 - 2022 Apple Inc. and the Swift project authors
|
|
// Licensed under Apache License v2.0 with Runtime Library Exception
|
|
//
|
|
// See https://swift.org/LICENSE.txt for license information
|
|
// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
import SIL
|
|
import OptimizerBridging
|
|
|
|
/// The context which is passed to a `ModulePass`'s run-function.
|
|
///
|
|
/// It provides access to all functions, v-tables and witness tables of a module,
|
|
/// but it doesn't provide any APIs to modify functions.
|
|
/// In order to modify a function, a module pass must use `transform(function:)`.
|
|
struct ModulePassContext : Context, CustomStringConvertible {
|
|
let _bridged: BridgedPassContext
|
|
|
|
public var description: String {
|
|
let stdString = _bridged.getModuleDescription()
|
|
return String(_cxxString: stdString)
|
|
}
|
|
|
|
struct FunctionList : CollectionLikeSequence, IteratorProtocol {
|
|
private var currentFunction: Function?
|
|
|
|
fileprivate init(first: Function?) { currentFunction = first }
|
|
|
|
mutating func next() -> Function? {
|
|
if let f = currentFunction {
|
|
currentFunction = BridgedPassContext.getNextFunctionInModule(f.bridged).function
|
|
return f
|
|
}
|
|
return nil
|
|
}
|
|
}
|
|
|
|
struct GlobalVariableList : CollectionLikeSequence, IteratorProtocol {
|
|
private var currentGlobal: GlobalVariable?
|
|
|
|
fileprivate init(first: GlobalVariable?) { currentGlobal = first }
|
|
|
|
mutating func next() -> GlobalVariable? {
|
|
if let g = currentGlobal {
|
|
currentGlobal = BridgedPassContext.getNextGlobalInModule(g.bridged).globalVar
|
|
return g
|
|
}
|
|
return nil
|
|
}
|
|
}
|
|
|
|
struct VTableArray : BridgedRandomAccessCollection {
|
|
fileprivate let bridged: BridgedPassContext.VTableArray
|
|
|
|
var startIndex: Int { return 0 }
|
|
var endIndex: Int { return bridged.count }
|
|
|
|
subscript(_ index: Int) -> VTable {
|
|
assert(index >= startIndex && index < endIndex)
|
|
return VTable(bridged: BridgedVTable(vTable: bridged.base![index]))
|
|
}
|
|
}
|
|
|
|
struct WitnessTableList : CollectionLikeSequence, IteratorProtocol {
|
|
private var currentTable: WitnessTable?
|
|
|
|
fileprivate init(first: WitnessTable?) { currentTable = first }
|
|
|
|
mutating func next() -> WitnessTable? {
|
|
if let t = currentTable {
|
|
currentTable = BridgedPassContext.getNextWitnessTableInModule(t.bridged).witnessTable
|
|
return t
|
|
}
|
|
return nil
|
|
}
|
|
}
|
|
|
|
struct DefaultWitnessTableList : CollectionLikeSequence, IteratorProtocol {
|
|
private var currentTable: DefaultWitnessTable?
|
|
|
|
fileprivate init(first: DefaultWitnessTable?) { currentTable = first }
|
|
|
|
mutating func next() -> DefaultWitnessTable? {
|
|
if let t = currentTable {
|
|
currentTable = BridgedPassContext.getNextDefaultWitnessTableInModule(t.bridged).defaultWitnessTable
|
|
return t
|
|
}
|
|
return nil
|
|
}
|
|
}
|
|
|
|
var functions: FunctionList {
|
|
FunctionList(first: _bridged.getFirstFunctionInModule().function)
|
|
}
|
|
|
|
var globalVariables: GlobalVariableList {
|
|
GlobalVariableList(first: _bridged.getFirstGlobalInModule().globalVar)
|
|
}
|
|
|
|
var vTables: VTableArray {
|
|
VTableArray(bridged: _bridged.getVTables())
|
|
}
|
|
|
|
var witnessTables: WitnessTableList {
|
|
WitnessTableList(first: _bridged.getFirstWitnessTableInModule().witnessTable)
|
|
}
|
|
|
|
var defaultWitnessTables: DefaultWitnessTableList {
|
|
DefaultWitnessTableList(first: _bridged.getFirstDefaultWitnessTableInModule().defaultWitnessTable)
|
|
}
|
|
|
|
/// Run a closure with a `PassContext` for a function, which allows to modify that function.
|
|
///
|
|
/// Only a single `transform` can be alive at the same time, i.e. it's not allowed to nest
|
|
/// calls to `transform`.
|
|
func transform(function: Function, _ runOnFunction: (FunctionPassContext) -> ()) {
|
|
_bridged.beginTransformFunction(function.bridged)
|
|
runOnFunction(FunctionPassContext(_bridged: _bridged))
|
|
_bridged.endTransformFunction();
|
|
}
|
|
|
|
func mangleAsyncRemoved(from function: Function) -> String {
|
|
let stdString = _bridged.mangleAsyncRemoved(function.bridged)
|
|
return String(_cxxString: stdString)
|
|
}
|
|
}
|
|
|
|
extension GlobalVariable {
|
|
func setIsLet(to value: Bool, _ context: ModulePassContext) {
|
|
bridged.setLet(value)
|
|
}
|
|
}
|