mirror of
https://github.com/apple/swift.git
synced 2025-12-14 20:36:38 +01:00
166 lines
5.4 KiB
Swift
166 lines
5.4 KiB
Swift
//===--- CalleeAnalysis.swift - the callee analysis -----------------------===//
|
|
//
|
|
// This source file is part of the Swift.org open source project
|
|
//
|
|
// Copyright (c) 2014 - 2021 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 OptimizerBridging
|
|
import SIL
|
|
|
|
public struct CalleeAnalysis {
|
|
let bridged: BridgedCalleeAnalysis
|
|
|
|
static func register() {
|
|
BridgedCalleeAnalysis.registerAnalysis(
|
|
// isDeinitBarrierFn:
|
|
{ (inst : BridgedInstruction, bca: BridgedCalleeAnalysis) -> Bool in
|
|
return inst.instruction.isDeinitBarrier(bca.analysis)
|
|
},
|
|
// getMemBehaviorFn
|
|
{ (bridgedApply: BridgedInstruction, observeRetains: Bool, bca: BridgedCalleeAnalysis) -> BridgedMemoryBehavior in
|
|
let apply = bridgedApply.instruction as! ApplySite
|
|
let e = bca.analysis.getSideEffects(ofApply: apply)
|
|
return e.getMemBehavior(observeRetains: observeRetains)
|
|
}
|
|
)
|
|
}
|
|
|
|
public func getCallees(callee: Value) -> FunctionArray? {
|
|
let bridgedFuncs = bridged.getCallees(callee.bridged)
|
|
if bridgedFuncs.isIncomplete() {
|
|
return nil
|
|
}
|
|
return FunctionArray(bridged: bridgedFuncs)
|
|
}
|
|
|
|
public func getIncompleteCallees(callee: Value) -> FunctionArray {
|
|
return FunctionArray(bridged: bridged.getCallees(callee.bridged))
|
|
}
|
|
|
|
public func getDestructor(ofExactType type: Type) -> Function? {
|
|
let destructors = FunctionArray(bridged: bridged.getDestructors(type.bridged, /*isExactType*/ true))
|
|
if destructors.count == 1 {
|
|
return destructors[0]
|
|
}
|
|
return nil
|
|
}
|
|
|
|
public func getDestructors(of type: Type) -> FunctionArray? {
|
|
let bridgedDtors = bridged.getDestructors(type.bridged, /*isExactType*/ false)
|
|
if bridgedDtors.isIncomplete() {
|
|
return nil
|
|
}
|
|
return FunctionArray(bridged: bridgedDtors)
|
|
}
|
|
|
|
/// Returns the global (i.e. not argument specific) side effects of an apply.
|
|
public func getSideEffects(ofApply apply: ApplySite) -> SideEffects.GlobalEffects {
|
|
return getSideEffects(ofCallee: apply.callee)
|
|
}
|
|
|
|
public func getSideEffects(ofCallee callee: Value) -> SideEffects.GlobalEffects {
|
|
guard let callees = getCallees(callee: callee) else {
|
|
return .worstEffects
|
|
}
|
|
|
|
var result = SideEffects.GlobalEffects()
|
|
for callee in callees {
|
|
let calleeEffects = callee.getSideEffects()
|
|
result.merge(with: calleeEffects)
|
|
}
|
|
return result
|
|
}
|
|
|
|
/// Returns the argument specific side effects of an apply.
|
|
public func getSideEffects(of apply: ApplySite, operand: Operand, path: SmallProjectionPath) -> SideEffects.GlobalEffects {
|
|
var result = SideEffects.GlobalEffects()
|
|
guard let calleeArgIdx = apply.calleeArgumentIndex(of: operand) else {
|
|
return result
|
|
}
|
|
let convention = apply.convention(of: operand)!
|
|
let argument = operand.value.at(path)
|
|
|
|
guard let callees = getCallees(callee: apply.callee) else {
|
|
return .worstEffects.restrictedTo(argument: argument, withConvention: convention)
|
|
}
|
|
|
|
for callee in callees {
|
|
let calleeEffects = callee.getSideEffects(forArgument: argument,
|
|
atIndex: calleeArgIdx,
|
|
withConvention: convention)
|
|
result.merge(with: calleeEffects)
|
|
}
|
|
return result.restrictedTo(argument: argument, withConvention: convention)
|
|
}
|
|
}
|
|
|
|
extension Value {
|
|
fileprivate func isBarrier(_ analysis: CalleeAnalysis) -> Bool {
|
|
guard let callees = analysis.getCallees(callee: self) else {
|
|
return true
|
|
}
|
|
return callees.contains { $0.isDeinitBarrier }
|
|
}
|
|
}
|
|
|
|
extension FullApplySite {
|
|
fileprivate func isBarrier(_ analysis: CalleeAnalysis) -> Bool {
|
|
return callee.isBarrier(analysis)
|
|
}
|
|
}
|
|
|
|
extension EndApplyInst {
|
|
fileprivate func isBarrier(_ analysis: CalleeAnalysis) -> Bool {
|
|
return (operand.value.definingInstruction as! FullApplySite).isBarrier(analysis)
|
|
}
|
|
}
|
|
|
|
extension AbortApplyInst {
|
|
fileprivate func isBarrier(_ analysis: CalleeAnalysis) -> Bool {
|
|
return (operand.value.definingInstruction as! FullApplySite).isBarrier(analysis)
|
|
}
|
|
}
|
|
|
|
extension Instruction {
|
|
/// Whether lifetime ends of lexical values may safely be hoisted over this
|
|
/// instruction.
|
|
///
|
|
/// Deinitialization barriers constrain variable lifetimes. Lexical
|
|
/// end_borrow, destroy_value, and destroy_addr cannot be hoisted above them.
|
|
public final func isDeinitBarrier(_ analysis: CalleeAnalysis) -> Bool {
|
|
if let site = self as? FullApplySite {
|
|
return site.isBarrier(analysis)
|
|
}
|
|
if let eai = self as? EndApplyInst {
|
|
return eai.isBarrier(analysis)
|
|
}
|
|
if let aai = self as? AbortApplyInst {
|
|
return aai.isBarrier(analysis)
|
|
}
|
|
return mayAccessPointer || mayLoadWeakOrUnowned || maySynchronize
|
|
}
|
|
}
|
|
|
|
public struct FunctionArray : RandomAccessCollection, FormattedLikeArray {
|
|
fileprivate let bridged: BridgedCalleeAnalysis.CalleeList
|
|
|
|
public var startIndex: Int { 0 }
|
|
public var endIndex: Int { bridged.getCount() }
|
|
|
|
public subscript(_ index: Int) -> Function {
|
|
return bridged.getCallee(index).function
|
|
}
|
|
}
|
|
// Bridging utilities
|
|
|
|
extension BridgedCalleeAnalysis {
|
|
public var analysis: CalleeAnalysis { .init(bridged: self) }
|
|
}
|
|
|