mirror of
https://github.com/apple/swift.git
synced 2025-12-14 20:36:38 +01:00
317 lines
11 KiB
Swift
317 lines
11 KiB
Swift
//===--- Context.swift - defines the context types ------------------------===//
|
|
//
|
|
// 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 AST
|
|
import SIL
|
|
import OptimizerBridging
|
|
|
|
extension Context {
|
|
var bridgedPassContext: BridgedPassContext {
|
|
BridgedPassContext(_bridged)
|
|
}
|
|
|
|
var options: Options { Options(_bridged: bridgedPassContext) }
|
|
|
|
var diagnosticEngine: DiagnosticEngine {
|
|
return DiagnosticEngine(bridged: bridgedPassContext.getDiagnosticEngine())
|
|
}
|
|
|
|
// The calleeAnalysis is not specific to a function and therefore can be provided in
|
|
// all contexts.
|
|
var calleeAnalysis: CalleeAnalysis {
|
|
let bridgeCA = bridgedPassContext.getCalleeAnalysis()
|
|
return CalleeAnalysis(bridged: bridgeCA)
|
|
}
|
|
|
|
var hadError: Bool { bridgedPassContext.hadError() }
|
|
|
|
/// Enable diagnostics requiring WMO (for @noLocks, @noAllocation
|
|
/// annotations, Embedded Swift, and class specialization). SourceKit is the
|
|
/// only consumer that has this disabled today (as it disables WMO
|
|
/// explicitly).
|
|
var enableWMORequiredDiagnostics: Bool {
|
|
bridgedPassContext.enableWMORequiredDiagnostics()
|
|
}
|
|
|
|
func canMakeStaticObjectReadOnly(objectType: Type) -> Bool {
|
|
bridgedPassContext.canMakeStaticObjectReadOnly(objectType.bridged)
|
|
}
|
|
|
|
func notifyNewFunction(function: Function, derivedFrom: Function) {
|
|
bridgedPassContext.addFunctionToPassManagerWorklist(function.bridged, derivedFrom.bridged)
|
|
}
|
|
}
|
|
|
|
extension MutatingContext {
|
|
func notifyInvalidatedStackNesting() { bridgedPassContext.notifyInvalidatedStackNesting() }
|
|
var needFixStackNesting: Bool { bridgedPassContext.getNeedFixStackNesting() }
|
|
|
|
func tryOptimizeApplyOfPartialApply(closure: PartialApplyInst) -> Bool {
|
|
if bridgedPassContext.tryOptimizeApplyOfPartialApply(closure.bridged) {
|
|
notifyInstructionsChanged()
|
|
notifyCallsChanged()
|
|
|
|
for use in closure.callee.uses {
|
|
if use.instruction is FullApplySite {
|
|
notifyInstructionChanged(use.instruction)
|
|
}
|
|
}
|
|
return true
|
|
}
|
|
return false
|
|
}
|
|
|
|
func tryDeleteDeadClosure(closure: SingleValueInstruction, needKeepArgsAlive: Bool = true) -> Bool {
|
|
if bridgedPassContext.tryDeleteDeadClosure(closure.bridged, needKeepArgsAlive) {
|
|
notifyInstructionsChanged()
|
|
return true
|
|
}
|
|
return false
|
|
}
|
|
|
|
func tryDevirtualize(apply: FullApplySite, isMandatory: Bool) -> ApplySite? {
|
|
let result = bridgedPassContext.tryDevirtualizeApply(apply.bridged, isMandatory)
|
|
if let newApply = result.newApply.instruction {
|
|
erase(instruction: apply)
|
|
notifyInstructionsChanged()
|
|
notifyCallsChanged()
|
|
if result.cfgChanged {
|
|
notifyBranchesChanged()
|
|
}
|
|
notifyInstructionChanged(newApply)
|
|
return newApply as! FullApplySite
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func tryOptimizeKeypath(apply: FullApplySite) -> Bool {
|
|
return bridgedPassContext.tryOptimizeKeypath(apply.bridged)
|
|
}
|
|
|
|
func inlineFunction(apply: FullApplySite, mandatoryInline: Bool) {
|
|
// This is only a best-effort attempt to notify the new cloned instructions as changed.
|
|
// TODO: get a list of cloned instructions from the `inlineFunction`
|
|
let instAfterInling: Instruction?
|
|
switch apply {
|
|
case is ApplyInst:
|
|
instAfterInling = apply.next
|
|
case let beginApply as BeginApplyInst:
|
|
let next = beginApply.next!
|
|
instAfterInling = (next is EndApplyInst ? nil : next)
|
|
case is TryApplyInst:
|
|
instAfterInling = apply.parentBlock.next?.instructions.first
|
|
default:
|
|
instAfterInling = nil
|
|
}
|
|
|
|
bridgedPassContext.inlineFunction(apply.bridged, mandatoryInline)
|
|
|
|
if let instAfterInling = instAfterInling {
|
|
notifyNewInstructions(from: apply, to: instAfterInling)
|
|
}
|
|
}
|
|
|
|
func loadFunction(function: Function, loadCalleesRecursively: Bool) -> Bool {
|
|
if function.isDefinition {
|
|
return true
|
|
}
|
|
_bridged.loadFunction(function.bridged, loadCalleesRecursively)
|
|
return function.isDefinition
|
|
}
|
|
|
|
private func notifyNewInstructions(from: Instruction, to: Instruction) {
|
|
var inst = from
|
|
while inst != to {
|
|
if !inst.isDeleted {
|
|
notifyInstructionChanged(inst)
|
|
}
|
|
if let next = inst.next {
|
|
inst = next
|
|
} else {
|
|
inst = inst.parentBlock.next!.instructions.first!
|
|
}
|
|
}
|
|
}
|
|
|
|
func getContextSubstitutionMap(for type: Type) -> SubstitutionMap {
|
|
SubstitutionMap(bridged: _bridged.getContextSubstitutionMap(type.bridged))
|
|
}
|
|
|
|
/// Notifies the pass manager that the optimization result of the current pass depends
|
|
/// on the body (i.e. SIL instructions) of another function than the currently optimized one.
|
|
func notifyDependency(onBodyOf otherFunction: Function) {
|
|
bridgedPassContext.notifyDependencyOnBodyOf(otherFunction.bridged)
|
|
}
|
|
}
|
|
|
|
/// The context which is passed to the run-function of a FunctionPass.
|
|
struct FunctionPassContext : MutatingContext {
|
|
let _bridged: BridgedContext
|
|
|
|
// A no-op.
|
|
var notifyInstructionChanged: (Instruction) -> () { return { inst in } }
|
|
|
|
func continueWithNextSubpassRun(for inst: Instruction? = nil) -> Bool {
|
|
return bridgedPassContext.continueWithNextSubpassRun(inst.bridged)
|
|
}
|
|
|
|
func createSimplifyContext(preserveDebugInfo: Bool,
|
|
notifyInstructionChanged: @escaping (Instruction) -> ()
|
|
) -> SimplifyContext {
|
|
SimplifyContext(_bridged: _bridged, notifyInstructionChanged: notifyInstructionChanged,
|
|
preserveDebugInfo: preserveDebugInfo)
|
|
}
|
|
|
|
var deadEndBlocks: DeadEndBlocksAnalysis {
|
|
let bridgeDEA = bridgedPassContext.getDeadEndBlocksAnalysis()
|
|
return DeadEndBlocksAnalysis(bridged: bridgeDEA)
|
|
}
|
|
|
|
var dominatorTree: DominatorTree {
|
|
let bridgedDT = bridgedPassContext.getDomTree()
|
|
return DominatorTree(bridged: bridgedDT)
|
|
}
|
|
|
|
var postDominatorTree: PostDominatorTree {
|
|
let bridgedPDT = bridgedPassContext.getPostDomTree()
|
|
return PostDominatorTree(bridged: bridgedPDT)
|
|
}
|
|
|
|
func loadFunction(name: StaticString, loadCalleesRecursively: Bool) -> Function? {
|
|
return name.withUTF8Buffer { (nameBuffer: UnsafeBufferPointer<UInt8>) in
|
|
let nameStr = BridgedStringRef(data: nameBuffer.baseAddress, count: nameBuffer.count)
|
|
return _bridged.loadFunction(nameStr, loadCalleesRecursively).function
|
|
}
|
|
}
|
|
|
|
func eliminateDeadAllocations(in function: Function) -> Bool {
|
|
if bridgedPassContext.eliminateDeadAllocations(function.bridged) {
|
|
notifyInstructionsChanged()
|
|
return true
|
|
}
|
|
return false
|
|
}
|
|
|
|
func specializeClassMethodInst(_ cm: ClassMethodInst) -> Bool {
|
|
if bridgedPassContext.specializeClassMethodInst(cm.bridged) {
|
|
notifyInstructionsChanged()
|
|
notifyCallsChanged()
|
|
return true
|
|
}
|
|
return false
|
|
}
|
|
|
|
func specializeWitnessMethodInst(_ wm: WitnessMethodInst) -> Bool {
|
|
if bridgedPassContext.specializeWitnessMethodInst(wm.bridged) {
|
|
notifyInstructionsChanged()
|
|
notifyCallsChanged()
|
|
return true
|
|
}
|
|
return false
|
|
}
|
|
|
|
func specializeApplies(in function: Function, isMandatory: Bool) -> Bool {
|
|
if bridgedPassContext.specializeAppliesInFunction(function.bridged, isMandatory) {
|
|
notifyInstructionsChanged()
|
|
notifyCallsChanged()
|
|
return true
|
|
}
|
|
return false
|
|
}
|
|
|
|
func mangleOutlinedVariable(from function: Function) -> String {
|
|
return String(taking: bridgedPassContext.mangleOutlinedVariable(function.bridged))
|
|
}
|
|
|
|
func mangle(withClosureArguments closureArgs: [Value], closureArgIndices: [Int], from applySiteCallee: Function) -> String {
|
|
closureArgs.withBridgedValues { bridgedClosureArgsRef in
|
|
closureArgIndices.withBridgedArrayRef{bridgedClosureArgIndicesRef in
|
|
String(taking: bridgedPassContext.mangleWithClosureArgs(
|
|
bridgedClosureArgsRef,
|
|
bridgedClosureArgIndicesRef,
|
|
applySiteCallee.bridged
|
|
))
|
|
}
|
|
}
|
|
}
|
|
|
|
func mangle(withBoxToStackPromotedArguments argIndices: [Int], from original: Function) -> String {
|
|
argIndices.withBridgedArrayRef { bridgedArgIndices in
|
|
String(taking: bridgedPassContext.mangleWithBoxToStackPromotedArgs(bridgedArgIndices, original.bridged))
|
|
}
|
|
}
|
|
|
|
func createSpecializedFunctionDeclaration(from original: Function, withName specializedFunctionName: String,
|
|
withParams specializedParameters: [ParameterInfo],
|
|
makeThin: Bool = false,
|
|
makeBare: Bool = false) -> Function
|
|
{
|
|
return specializedFunctionName._withBridgedStringRef { nameRef in
|
|
let bridgedParamInfos = specializedParameters.map { $0._bridged }
|
|
|
|
return bridgedParamInfos.withUnsafeBufferPointer { paramBuf in
|
|
bridgedPassContext.createSpecializedFunctionDeclaration(nameRef, paramBuf.baseAddress, paramBuf.count,
|
|
original.bridged, makeThin, makeBare).function
|
|
}
|
|
}
|
|
}
|
|
|
|
func buildSpecializedFunction<T>(specializedFunction: Function, buildFn: (Function, FunctionPassContext) -> T) -> T {
|
|
let nestedBridgedContext = bridgedPassContext.initializeNestedPassContext(specializedFunction.bridged)
|
|
let nestedContext = FunctionPassContext(_bridged: nestedBridgedContext)
|
|
defer { bridgedPassContext.deinitializedNestedPassContext() }
|
|
|
|
return buildFn(specializedFunction, nestedContext)
|
|
}
|
|
|
|
/// Makes sure that the lifetime of `value` ends at all control flow paths, even in dead-end blocks.
|
|
/// Inserts destroys in dead-end blocks if those are missing.
|
|
func completeLifetime(of value: Value) {
|
|
if bridgedPassContext.completeLifetime(value.bridged) {
|
|
notifyInstructionsChanged()
|
|
}
|
|
}
|
|
|
|
func fixStackNesting(in function: Function) {
|
|
bridgedPassContext.fixStackNesting(function.bridged)
|
|
}
|
|
}
|
|
|
|
struct SimplifyContext : MutatingContext {
|
|
let _bridged: BridgedContext
|
|
let notifyInstructionChanged: (Instruction) -> ()
|
|
let preserveDebugInfo: Bool
|
|
|
|
func constantFold(builtin: BuiltinInst) -> Value? {
|
|
bridgedPassContext.constantFoldBuiltin(builtin.bridged).value
|
|
}
|
|
}
|
|
|
|
// Those Type APIs get information from IRGenModule, so they are formally not part of SIL and
|
|
// therefore need to be defined here, in the Optimizer module.
|
|
extension Type {
|
|
func getStaticSize(context: SimplifyContext) -> Int? {
|
|
let v = context.bridgedPassContext.getStaticSize(self.bridged)
|
|
return v == -1 ? nil : v
|
|
}
|
|
|
|
func getStaticAlignment(context: SimplifyContext) -> Int? {
|
|
let v = context.bridgedPassContext.getStaticAlignment(self.bridged)
|
|
return v == -1 ? nil : v
|
|
}
|
|
|
|
func getStaticStride(context: SimplifyContext) -> Int? {
|
|
let v = context.bridgedPassContext.getStaticStride(self.bridged)
|
|
return v == -1 ? nil : v
|
|
}
|
|
}
|