1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165
|
//===--- 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) }
}
|