Add new generalized cloner.

This commit is contained in:
Jakub Florek
2025-08-28 20:57:57 +01:00
parent bc86fe5a38
commit e3140e0ae0
15 changed files with 322 additions and 257 deletions

View File

@@ -311,10 +311,9 @@ private struct FunctionSpecializations {
// This can happen if a previous run of the pass already created this specialization. // This can happen if a previous run of the pass already created this specialization.
return return
} }
let cloner = SpecializationCloner(emptySpecializedFunction: specializedFunc, context)
cloner.cloneFunctionBody(from: original)
context.buildSpecializedFunction(specializedFunction: specializedFunc) { (specializedFunc, specContext) in context.buildSpecializedFunction(specializedFunction: specializedFunc) { (specializedFunc, specContext) in
cloneFunction(from: original, toEmpty: specializedFunc, specContext)
replaceBoxWithStackArguments(in: specializedFunc, original: original, specContext) replaceBoxWithStackArguments(in: specializedFunc, original: original, specContext)
} }
context.notifyNewFunction(function: specializedFunc, derivedFrom: original) context.notifyNewFunction(function: specializedFunc, derivedFrom: original)

View File

@@ -247,9 +247,10 @@ private func getOrCreateSpecializedFunction(
context.buildSpecializedFunction( context.buildSpecializedFunction(
specializedFunction: specializedFunction, specializedFunction: specializedFunction,
buildFn: { (emptySpecializedFunction, functionPassContext) in buildFn: { (emptySpecializedFunction, functionPassContext) in
let closureSpecCloner = SpecializationCloner( var closureSpecCloner = Cloner(
emptySpecializedFunction: emptySpecializedFunction, functionPassContext) cloneToEmptyFunction: emptySpecializedFunction, functionPassContext)
closureSpecCloner.cloneAndSpecializeFunctionBody(using: pullbackClosureInfo) closureSpecCloner.cloneAndSpecializeFunctionBody(using: pullbackClosureInfo)
closureSpecCloner.deinitialize()
}) })
return (specializedFunction, false) return (specializedFunction, false)
@@ -731,15 +732,14 @@ private func markConvertedAndReabstractedClosuresAsUsed(
} }
} }
extension SpecializationCloner { extension Cloner where Context == FunctionPassContext {
fileprivate func cloneAndSpecializeFunctionBody(using pullbackClosureInfo: PullbackClosureInfo) { fileprivate func cloneAndSpecializeFunctionBody(using pullbackClosureInfo: PullbackClosureInfo) {
self.cloneEntryBlockArgsWithoutOrigClosures(usingOrigCalleeAt: pullbackClosureInfo) self.cloneEntryBlockArgsWithoutOrigClosures(usingOrigCalleeAt: pullbackClosureInfo)
let (allSpecializedEntryBlockArgs, closureArgIndexToAllClonedReleasableClosures) = let (allSpecializedEntryBlockArgs, closureArgIndexToAllClonedReleasableClosures) =
cloneAllClosures(at: pullbackClosureInfo) cloneAllClosures(at: pullbackClosureInfo)
self.cloneFunctionBody( self.cloneFunctionBody(from: pullbackClosureInfo.pullbackFn, entryBlockArguments: allSpecializedEntryBlockArgs)
from: pullbackClosureInfo.pullbackFn, entryBlockArguments: allSpecializedEntryBlockArgs)
self.insertCleanupCodeForClonedReleasableClosures( self.insertCleanupCodeForClonedReleasableClosures(
from: pullbackClosureInfo, from: pullbackClosureInfo,
@@ -750,8 +750,8 @@ extension SpecializationCloner {
usingOrigCalleeAt pullbackClosureInfo: PullbackClosureInfo usingOrigCalleeAt pullbackClosureInfo: PullbackClosureInfo
) { ) {
let originalEntryBlock = pullbackClosureInfo.pullbackFn.entryBlock let originalEntryBlock = pullbackClosureInfo.pullbackFn.entryBlock
let clonedFunction = self.cloned let clonedFunction = self.targetFunction
let clonedEntryBlock = self.entryBlock let clonedEntryBlock = self.getOrCreateEntryBlock()
originalEntryBlock.arguments originalEntryBlock.arguments
.enumerated() .enumerated()
@@ -782,7 +782,8 @@ extension SpecializationCloner {
) )
{ {
func entryBlockArgsWithOrigClosuresSkipped() -> [Value?] { func entryBlockArgsWithOrigClosuresSkipped() -> [Value?] {
var clonedNonClosureEntryBlockArgs = self.entryBlock.arguments.makeIterator() let clonedEntryBlock = self.getOrCreateEntryBlock()
var clonedNonClosureEntryBlockArgs = clonedEntryBlock.arguments.makeIterator()
return pullbackClosureInfo.pullbackFn return pullbackClosureInfo.pullbackFn
.entryBlock .entryBlock
@@ -823,8 +824,8 @@ extension SpecializationCloner {
{ {
let (origToClonedValueMap, capturedArgRange) = self.addEntryBlockArgs( let (origToClonedValueMap, capturedArgRange) = self.addEntryBlockArgs(
forValuesCapturedBy: closureArgDesc) forValuesCapturedBy: closureArgDesc)
let clonedFunction = self.cloned let clonedFunction = self.targetFunction
let clonedEntryBlock = self.entryBlock let clonedEntryBlock = self.getOrCreateEntryBlock()
let clonedClosureArgs = Array(clonedEntryBlock.arguments[capturedArgRange]) let clonedClosureArgs = Array(clonedEntryBlock.arguments[capturedArgRange])
let builder = let builder =
@@ -853,8 +854,8 @@ extension SpecializationCloner {
-> (origToClonedValueMap: [HashableValue: Value], capturedArgRange: Range<Int>) -> (origToClonedValueMap: [HashableValue: Value], capturedArgRange: Range<Int>)
{ {
var origToClonedValueMap: [HashableValue: Value] = [:] var origToClonedValueMap: [HashableValue: Value] = [:]
let clonedFunction = self.cloned let clonedFunction = self.targetFunction
let clonedEntryBlock = self.entryBlock let clonedEntryBlock = self.getOrCreateEntryBlock()
let capturedArgRangeStart = clonedEntryBlock.arguments.count let capturedArgRangeStart = clonedEntryBlock.arguments.count
@@ -908,8 +909,8 @@ extension SpecializationCloner {
} }
} }
if self.context.needFixStackNesting { if (self.context.needFixStackNesting) {
self.context.fixStackNesting(in: self.cloned) self.context.fixStackNesting(in: targetFunction)
} }
} }
} }
@@ -1425,12 +1426,10 @@ private struct PullbackClosureInfo {
} }
func specializedCalleeName(_ context: FunctionPassContext) -> String { func specializedCalleeName(_ context: FunctionPassContext) -> String {
let closureArgs = Array(self.closureArgDescriptors.map { $0.closure }) let closureArgs = Array(self.closureArgDescriptors.map {
let closureIndices = Array(self.closureArgDescriptors.map { $0.closureArgIndex }) (argumentIndex: $0.closureArgIndex, argumentValue: $0.closure)
})
return context.mangle( return context.mangle(withClosureArguments: closureArgs, from: pullbackFn)
withClosureArguments: closureArgs, closureArgIndices: closureIndices,
from: pullbackFn)
} }
} }

View File

@@ -271,7 +271,7 @@ private indirect enum GlobalInitValue {
/// Creates SIL for this global init value in the initializer of the `global`. /// Creates SIL for this global init value in the initializer of the `global`.
func materialize(into global: GlobalVariable, from function: Function, _ context: FunctionPassContext) { func materialize(into global: GlobalVariable, from function: Function, _ context: FunctionPassContext) {
var cloner = StaticInitCloner(cloneTo: global, context) var cloner = Cloner(cloneToGlobal: global, context)
defer { cloner.deinitialize() } defer { cloner.deinitialize() }
let builder = Builder(staticInitializerOf: global, context) let builder = Builder(staticInitializerOf: global, context)
@@ -280,7 +280,7 @@ private indirect enum GlobalInitValue {
private func materializeRecursively( private func materializeRecursively(
type: Type, type: Type,
_ cloner: inout StaticInitCloner<FunctionPassContext>, _ cloner: inout Cloner<FunctionPassContext>,
_ builder: Builder, _ builder: Builder,
_ function: Function _ function: Function
) -> Value { ) -> Value {
@@ -289,7 +289,7 @@ private indirect enum GlobalInitValue {
fatalError("cannot materialize undefined init value") fatalError("cannot materialize undefined init value")
case .constant(let value): case .constant(let value):
return cloner.clone(value) return cloner.cloneRecursivelyToGlobal(value: value)
case .aggregate(let fields): case .aggregate(let fields):
if type.isStruct { if type.isStruct {

View File

@@ -364,13 +364,13 @@ private func constructObject(of allocRef: AllocRefInstBase,
inInitializerOf global: GlobalVariable, inInitializerOf global: GlobalVariable,
_ storesToClassFields: [StoreInst], _ storesToTailElements: [StoreInst], _ storesToClassFields: [StoreInst], _ storesToTailElements: [StoreInst],
_ context: FunctionPassContext) { _ context: FunctionPassContext) {
var cloner = StaticInitCloner(cloneTo: global, context) var cloner = Cloner(cloneToGlobal: global, context)
defer { cloner.deinitialize() } defer { cloner.deinitialize() }
// Create the initializers for the fields // Create the initializers for the fields
var objectArgs = [Value]() var objectArgs = [Value]()
for store in storesToClassFields { for store in storesToClassFields {
objectArgs.append(cloner.clone(store.source as! SingleValueInstruction)) objectArgs.append(cloner.cloneRecursivelyToGlobal(value: store.source as! SingleValueInstruction))
} }
let globalBuilder = Builder(staticInitializerOf: global, context) let globalBuilder = Builder(staticInitializerOf: global, context)
@@ -382,7 +382,7 @@ private func constructObject(of allocRef: AllocRefInstBase,
for elementIdx in 0..<allocRef.numTailElements! { for elementIdx in 0..<allocRef.numTailElements! {
let tupleElems = (0..<numTailTupleElems).map { tupleIdx in let tupleElems = (0..<numTailTupleElems).map { tupleIdx in
let store = storesToTailElements[elementIdx * numTailTupleElems + tupleIdx] let store = storesToTailElements[elementIdx * numTailTupleElems + tupleIdx]
return cloner.clone(store.source as! SingleValueInstruction) return cloner.cloneRecursivelyToGlobal(value: store.source as! SingleValueInstruction)
} }
let tuple = globalBuilder.createTuple(type: allocRef.tailAllocatedTypes[0], elements: tupleElems) let tuple = globalBuilder.createTuple(type: allocRef.tailAllocatedTypes[0], elements: tupleElems)
objectArgs.append(tuple) objectArgs.append(tuple)
@@ -390,7 +390,7 @@ private func constructObject(of allocRef: AllocRefInstBase,
} else { } else {
// The non-tuple element case. // The non-tuple element case.
for store in storesToTailElements { for store in storesToTailElements {
objectArgs.append(cloner.clone(store.source as! SingleValueInstruction)) objectArgs.append(cloner.cloneRecursivelyToGlobal(value: store.source as! SingleValueInstruction))
} }
} }
} }

View File

@@ -104,10 +104,10 @@ extension LoadInst : OnoneSimplifiable, SILCombineSimplifiable {
if !globalInitVal.canBeCopied(into: parentFunction, context) { if !globalInitVal.canBeCopied(into: parentFunction, context) {
return false return false
} }
var cloner = StaticInitCloner(cloneBefore: self, context) var cloner = Cloner(cloneBefore: self, context)
defer { cloner.deinitialize() } defer { cloner.deinitialize() }
let initVal = cloner.clone(globalInitVal) let initVal = cloner.cloneRecursivelyToGlobal(value: globalInitVal)
uses.replaceAll(with: initVal, context) uses.replaceAll(with: initVal, context)
// Also erases a builtin "once" on which the global_addr depends on. This is fine // Also erases a builtin "once" on which the global_addr depends on. This is fine
@@ -323,7 +323,7 @@ private extension Value {
return false return false
} }
if let fri = value as? FunctionRefInst { if let fri = value as? FunctionRefInst {
if function.isAnySerialized, if function.isAnySerialized,
!fri.referencedFunction.hasValidLinkageForFragileRef(function.serializedKind) !fri.referencedFunction.hasValidLinkageForFragileRef(function.serializedKind)
{ {
return false return false
@@ -447,4 +447,3 @@ private func getGlobalInitialization(
} }
return nil return nil
} }

View File

@@ -152,3 +152,28 @@ extension MutatingContext {
bridgedPassContext.notifyDependencyOnBodyOf(otherFunction.bridged) bridgedPassContext.notifyDependencyOnBodyOf(otherFunction.bridged)
} }
} }
extension Cloner where Context == FunctionPassContext {
func getOrCreateEntryBlock() -> BasicBlock {
if let entryBlock = targetFunction.blocks.first {
return entryBlock
}
return targetFunction.appendNewBlock(context)
}
func cloneFunctionBody(from originalFunction: Function, entryBlockArguments: [Value]) {
entryBlockArguments.withBridgedValues { bridgedEntryBlockArgs in
let entryBlock = getOrCreateEntryBlock()
bridged.cloneFunctionBody(originalFunction.bridged, entryBlock.bridged, bridgedEntryBlockArgs)
}
}
func cloneFunctionBody(from originalFunction: Function) {
bridged.cloneFunctionBody(originalFunction.bridged)
}
}
func cloneFunction(from originalFunction: Function, toEmpty targetFunction: Function, _ context: FunctionPassContext) {
var cloner = Cloner(cloneToEmptyFunction: targetFunction, context)
defer { cloner.deinitialize() }
cloner.cloneFunctionBody(from: originalFunction)
}

View File

@@ -92,15 +92,11 @@ struct FunctionPassContext : MutatingContext {
return String(taking: bridgedPassContext.mangleOutlinedVariable(function.bridged)) return String(taking: bridgedPassContext.mangleOutlinedVariable(function.bridged))
} }
func mangle(withClosureArguments closureArgs: [Value], closureArgIndices: [Int], from applySiteCallee: Function) -> String { func mangle(withClosureArguments closureArgs: [(argumentIndex: Int, argumentValue: Value)],
closureArgs.withBridgedValues { bridgedClosureArgsRef in from applySiteCallee: Function
closureArgIndices.withBridgedArrayRef{bridgedClosureArgIndicesRef in ) -> String {
String(taking: bridgedPassContext.mangleWithClosureArgs( closureArgs.withBridgedArrayRef{ bridgedClosureArgs in
bridgedClosureArgsRef, String(taking: bridgedPassContext.mangleWithClosureArgs(bridgedClosureArgs, applySiteCallee.bridged))
bridgedClosureArgIndicesRef,
applySiteCallee.bridged
))
}
} }
} }

View File

@@ -8,7 +8,6 @@
swift_compiler_sources(Optimizer swift_compiler_sources(Optimizer
AddressUtils.swift AddressUtils.swift
SpecializationCloner.swift
Devirtualization.swift Devirtualization.swift
EscapeUtils.swift EscapeUtils.swift
FunctionSignatureTransforms.swift FunctionSignatureTransforms.swift
@@ -18,5 +17,4 @@ swift_compiler_sources(Optimizer
LocalVariableUtils.swift LocalVariableUtils.swift
OptUtils.swift OptUtils.swift
OwnershipLiveness.swift OwnershipLiveness.swift
StaticInitCloner.swift
) )

View File

@@ -1,52 +0,0 @@
//===--- SpecializationCloner.swift --------------------------------------------==//
//
// This source file is part of the Swift.org open source project
//
// Copyright (c) 2014 - 2024 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
/// Utility cloner type that can be used by optimizations that generate new functions or specialized versions of
/// existing functions.
struct SpecializationCloner {
private let bridged: BridgedSpecializationCloner
let context: FunctionPassContext
init(emptySpecializedFunction: Function, _ context: FunctionPassContext) {
self.bridged = BridgedSpecializationCloner(emptySpecializedFunction.bridged)
self.context = context
}
var cloned: Function {
bridged.getCloned().function
}
var entryBlock: BasicBlock {
if cloned.blocks.isEmpty {
return cloned.appendNewBlock(context)
} else {
return cloned.entryBlock
}
}
func getClonedBlock(for originalBlock: BasicBlock) -> BasicBlock {
bridged.getClonedBasicBlock(originalBlock.bridged).block
}
func cloneFunctionBody(from originalFunction: Function, entryBlockArguments: [Value]) {
entryBlockArguments.withBridgedValues { bridgedEntryBlockArgs in
bridged.cloneFunctionBody(originalFunction.bridged, self.entryBlock.bridged, bridgedEntryBlockArgs)
}
}
func cloneFunctionBody(from originalFunction: Function) {
bridged.cloneFunctionBody(originalFunction.bridged)
}
}

View File

@@ -1,78 +0,0 @@
//===--- StaticInitCloner.swift --------------------------------------------==//
//
// This source file is part of the Swift.org open source project
//
// Copyright (c) 2014 - 2023 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
/// Clones the initializer value of a GlobalVariable.
///
/// Used to transitively clone "constant" instructions, including their operands,
/// from or to the static initializer value of a GlobalVariable.
///
struct StaticInitCloner<Context: MutatingContext> {
private var bridged: BridgedCloner
private let context: Context
private let cloningIntoFunction: Bool
init(cloneTo global: GlobalVariable, _ context: Context) {
self.bridged = BridgedCloner(global.bridged, context._bridged)
self.context = context
self.cloningIntoFunction = false
}
init(cloneBefore inst: Instruction, _ context: Context) {
self.bridged = BridgedCloner(inst.bridged, context._bridged)
self.context = context
self.cloningIntoFunction = true
}
mutating func deinitialize() {
bridged.destroy(context._bridged)
}
/// Transitively clones `value` including its defining instruction's operands.
mutating func clone(_ value: Value) -> Value {
if isCloned(value: value) {
return getClonedValue(of: value)
}
if let beginAccess = value as? BeginAccessInst {
// Skip access instructions, which might be generated for UnsafePointer globals which point to other globals.
let clonedOperand = clone(beginAccess.address)
bridged.recordFoldedValue(beginAccess.bridged, clonedOperand.bridged)
return clonedOperand
}
let inst = value.definingInstruction!
assert(!(inst is ScopedInstruction), "global init value must not contain a scoped instruction")
for op in inst.operands {
_ = clone(op.value)
}
bridged.clone(inst.bridged)
let clonedValue = getClonedValue(of: value)
if cloningIntoFunction {
context.notifyInstructionChanged(clonedValue.definingInstruction!)
}
return clonedValue
}
mutating func getClonedValue(of value: Value) -> Value {
bridged.getClonedValue(value.bridged).value
}
func isCloned(value: Value) -> Bool {
bridged.isValueCloned(value.bridged)
}
}

View File

@@ -9,6 +9,7 @@
swift_compiler_sources(SIL swift_compiler_sources(SIL
AccessUtils.swift AccessUtils.swift
BorrowUtils.swift BorrowUtils.swift
Cloner.swift
ForwardingUtils.swift ForwardingUtils.swift
PhiUpdater.swift PhiUpdater.swift
SequenceUtilities.swift SequenceUtilities.swift

View File

@@ -0,0 +1,141 @@
//===--- Cloner.swift ------------------------------------------------------==//
//
// This source file is part of the Swift.org open source project
//
// Copyright (c) 2014 - 2024 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 SILBridging
/// Clones the initializer value of a GlobalVariable.
///
/// Used to transitively clone "constant" instructions, including their operands,
/// from or to the static initializer value of a GlobalVariable.
///
public struct Cloner<Context: MutatingContext> {
public var bridged: BridgedCloner
public let context: Context
public enum GetClonedResult {
case defaultValue
case customValue(Value)
case stopCloning
}
public enum Target {
case function(Function)
case global(GlobalVariable)
}
public let target: Target
public init(cloneToGlobal: GlobalVariable, _ context: Context) {
self.bridged = BridgedCloner(cloneToGlobal.bridged, context._bridged)
self.context = context
self.target = .global(cloneToGlobal)
}
public init(cloneBefore inst: Instruction, _ context: Context) {
self.bridged = BridgedCloner(inst.bridged, context._bridged)
self.context = context
self.target = .function(inst.parentFunction)
}
public init(cloneToEmptyFunction: Function, _ context: Context) {
self.bridged = BridgedCloner(cloneToEmptyFunction.bridged, context._bridged)
self.context = context
self.target = .function(cloneToEmptyFunction)
}
public mutating func deinitialize() {
bridged.destroy(context._bridged)
}
public var targetFunction: Function {
guard case .function(let function) = target else {
fatalError("expected cloning into a function")
}
return function
}
public mutating func clone(instruction: Instruction) -> Instruction {
let cloned = bridged.clone(instruction.bridged).instruction
if case .function = target {
context.notifyInstructionChanged(cloned)
context.notifyInstructionsChanged()
}
return cloned
}
public mutating func cloneRecursivelyToGlobal(value: Value) -> Value {
guard let cloned = cloneRecursively(value: value, customGetCloned: { value, cloner in
guard let beginAccess = value as? BeginAccessInst else {
return .defaultValue
}
// Skip access instructions, which might be generated for UnsafePointer globals which point to other globals.
let clonedOperand = cloner.cloneRecursivelyToGlobal(value: beginAccess.address)
cloner.recordFoldedValue(beginAccess, mappedTo: clonedOperand)
return .customValue(clonedOperand)
}) else {
fatalError("Clone recursively to global shouldn't bail.")
}
return cloned
}
/// Transitively clones `value` including its defining instruction's operands.
public mutating func cloneRecursively(value: Value, customGetCloned: (Value, inout Cloner) -> GetClonedResult) -> Value? {
if isCloned(value: value) {
return getClonedValue(of: value)
}
switch customGetCloned(value, &self) {
case .customValue(let base):
return base
case .stopCloning:
return nil
case .defaultValue:
break
}
guard let inst = value.definingInstruction else {
fatalError("expected instruction to clone or already cloned value")
}
for op in inst.operands {
if cloneRecursively(value: op.value, customGetCloned: customGetCloned) == nil {
return nil
}
}
let cloned = clone(instruction: inst)
if let svi = cloned as? SingleValueInstruction {
return svi
} else if let originalMvi = value as? MultipleValueInstructionResult {
return cloned.results[originalMvi.index]
}
fatalError("unexpected instruction kind")
}
public mutating func getClonedValue(of originalValue: Value) -> Value {
bridged.getClonedValue(originalValue.bridged).value
}
public func isCloned(value: Value) -> Bool {
bridged.isValueCloned(value.bridged)
}
public func getClonedBlock(for originalBlock: BasicBlock) -> BasicBlock {
bridged.getClonedBasicBlock(originalBlock.bridged).block
}
public func recordFoldedValue(_ origValue: Value, mappedTo mappedValue: Value) {
bridged.recordFoldedValue(origValue.bridged, mappedValue.bridged)
}
}

View File

@@ -60,6 +60,7 @@ class SymbolicValueBumpAllocator;
class ConstExprEvaluator; class ConstExprEvaluator;
class SILWitnessTable; class SILWitnessTable;
class SILDefaultWitnessTable; class SILDefaultWitnessTable;
class BridgedClonerImpl;
class SILDebugLocation; class SILDebugLocation;
class NominalTypeDecl; class NominalTypeDecl;
class VarDecl; class VarDecl;
@@ -1279,7 +1280,7 @@ struct BridgedBuilder{
BridgedArgumentConvention calleeConvention, BridgedArgumentConvention calleeConvention,
BridgedSubstitutionMap bridgedSubstitutionMap = BridgedSubstitutionMap(), BridgedSubstitutionMap bridgedSubstitutionMap = BridgedSubstitutionMap(),
bool hasUnknownIsolation = true, bool hasUnknownIsolation = true,
bool isOnStack = false) const; bool isOnStack = false) const;
SWIFT_IMPORT_UNSAFE BRIDGED_INLINE BridgedInstruction createBranch(BridgedBasicBlock destBlock, SWIFT_IMPORT_UNSAFE BRIDGED_INLINE BridgedInstruction createBranch(BridgedBasicBlock destBlock,
BridgedValueArray arguments) const; BridgedValueArray arguments) const;
SWIFT_IMPORT_UNSAFE BRIDGED_INLINE BridgedInstruction createUnreachable() const; SWIFT_IMPORT_UNSAFE BRIDGED_INLINE BridgedInstruction createUnreachable() const;
@@ -1376,18 +1377,6 @@ struct BridgedOperandSet {
SWIFT_IMPORT_UNSAFE BRIDGED_INLINE BridgedFunction getFunction() const; SWIFT_IMPORT_UNSAFE BRIDGED_INLINE BridgedFunction getFunction() const;
}; };
struct BridgedCloner {
swift::ClonerWithFixedLocation * _Nonnull cloner;
BridgedCloner(BridgedGlobalVar var, BridgedContext context);
BridgedCloner(BridgedInstruction inst, BridgedContext context);
void destroy(BridgedContext context);
SWIFT_IMPORT_UNSAFE BridgedValue getClonedValue(BridgedValue v);
bool isValueCloned(BridgedValue v) const;
void clone(BridgedInstruction inst);
void recordFoldedValue(BridgedValue origValue, BridgedValue mappedValue);
};
struct BridgedContext { struct BridgedContext {
swift::SILContext * _Nonnull context; swift::SILContext * _Nonnull context;
@@ -1501,6 +1490,25 @@ struct BridgedContext {
SWIFT_IMPORT_UNSAFE BRIDGED_INLINE Slab freeSlab(Slab slab) const; SWIFT_IMPORT_UNSAFE BRIDGED_INLINE Slab freeSlab(Slab slab) const;
}; };
struct BridgedCloner {
swift::BridgedClonerImpl * _Nonnull cloner;
BridgedCloner(BridgedGlobalVar var, BridgedContext context);
BridgedCloner(BridgedInstruction inst, BridgedContext context);
BridgedCloner(BridgedFunction emptyFunction, BridgedContext context);
void destroy(BridgedContext context);
SWIFT_IMPORT_UNSAFE BridgedFunction getCloned() const;
SWIFT_IMPORT_UNSAFE BridgedBasicBlock getClonedBasicBlock(BridgedBasicBlock originalBasicBlock) const;
void cloneFunctionBody(BridgedFunction originalFunction, BridgedBasicBlock clonedEntryBlock,
BridgedValueArray clonedEntryBlockArgs) const;
void cloneFunctionBody(BridgedFunction originalFunction) const;
SWIFT_IMPORT_UNSAFE BridgedValue getClonedValue(BridgedValue v);
bool isValueCloned(BridgedValue v) const;
void recordClonedInstruction(BridgedInstruction origInst, BridgedInstruction clonedInst) const;
void recordFoldedValue(BridgedValue orig, BridgedValue mapped) const;
BridgedInstruction clone(BridgedInstruction inst);
};
struct BridgedVerifier { struct BridgedVerifier {
typedef void (* _Nonnull VerifyFunctionFn)(BridgedContext, BridgedFunction); typedef void (* _Nonnull VerifyFunctionFn)(BridgedContext, BridgedFunction);

View File

@@ -546,59 +546,96 @@ BridgedInstruction BridgedBuilder::createSwitchEnumAddrInst(BridgedValue enumAdd
} }
//===----------------------------------------------------------------------===// //===----------------------------------------------------------------------===//
// BridgedCloner // BridgedCloner
//===----------------------------------------------------------------------===// //===----------------------------------------------------------------------===//
// Need to put ClonerWithFixedLocation into namespace swift to forward reference // Need to put ClonerWithFixedLocation into namespace swift to forward reference
// it in SILBridging.h. // it in OptimizerBridging.h.
namespace swift { namespace swift {
class ClonerWithFixedLocation : public SILCloner<ClonerWithFixedLocation> { class BridgedClonerImpl : public SILCloner<BridgedClonerImpl> {
friend class SILInstructionVisitor<ClonerWithFixedLocation>; friend class SILInstructionVisitor<BridgedClonerImpl>;
friend class SILCloner<ClonerWithFixedLocation>; friend class SILCloner<BridgedClonerImpl>;
SILDebugLocation insertLoc; bool hasFixedLocation;
union {
SILDebugLocation fixedLocation;
ScopeCloner scopeCloner;
};
SILInstruction *result = nullptr;
public: public:
ClonerWithFixedLocation(SILGlobalVariable *gVar) BridgedClonerImpl(SILGlobalVariable *gVar)
: SILCloner<ClonerWithFixedLocation>(gVar), : SILCloner<BridgedClonerImpl>(gVar),
insertLoc(ArtificialUnreachableLocation(), nullptr) {} hasFixedLocation(true),
fixedLocation(ArtificialUnreachableLocation(), nullptr) {}
ClonerWithFixedLocation(SILInstruction *insertionPoint) BridgedClonerImpl(SILInstruction *insertionPoint)
: SILCloner<ClonerWithFixedLocation>(*insertionPoint->getFunction()), : SILCloner<BridgedClonerImpl>(*insertionPoint->getFunction()),
insertLoc(insertionPoint->getDebugLocation()) { hasFixedLocation(true),
fixedLocation(insertionPoint->getDebugLocation()) {
Builder.setInsertionPoint(insertionPoint); Builder.setInsertionPoint(insertionPoint);
} }
BridgedClonerImpl(SILFunction &emptyFunction)
: SILCloner<BridgedClonerImpl>(emptyFunction),
hasFixedLocation(false),
scopeCloner(ScopeCloner(emptyFunction)) {}
~BridgedClonerImpl() {
if (hasFixedLocation) {
fixedLocation.~SILDebugLocation();
} else {
scopeCloner.~ScopeCloner();
}
}
SILValue getClonedValue(SILValue v) { SILValue getClonedValue(SILValue v) {
return getMappedValue(v); return getMappedValue(v);
} }
void cloneInst(SILInstruction *inst) { SILInstruction *cloneInst(SILInstruction *inst) {
result = nullptr;
visit(inst); visit(inst);
ASSERT(result && "instruction not cloned");
return result;
} }
protected:
SILLocation remapLocation(SILLocation loc) { SILLocation remapLocation(SILLocation loc) {
return insertLoc.getLocation(); if (hasFixedLocation)
return fixedLocation.getLocation();
return loc;
} }
const SILDebugScope *remapScope(const SILDebugScope *DS) { const SILDebugScope *remapScope(const SILDebugScope *DS) {
return insertLoc.getScope(); if (hasFixedLocation)
return fixedLocation.getScope();
return scopeCloner.getOrCreateClonedScope(DS);
} }
void postProcess(SILInstruction *Orig, SILInstruction *Cloned) {
result = Cloned;
SILCloner<BridgedClonerImpl>::postProcess(Orig, Cloned);
}
}; };
} // namespace swift } // namespace swift
BridgedCloner::BridgedCloner(BridgedGlobalVar var, BridgedContext context) BridgedCloner::BridgedCloner(BridgedGlobalVar var, BridgedContext context)
: cloner(new ClonerWithFixedLocation(var.getGlobal())) { : cloner(new BridgedClonerImpl(var.getGlobal())) {
context.context->notifyNewCloner(); context.context->notifyNewCloner();
} }
BridgedCloner::BridgedCloner(BridgedInstruction inst, BridgedCloner::BridgedCloner(BridgedInstruction inst,
BridgedContext context) BridgedContext context)
: cloner(new ClonerWithFixedLocation(inst.unbridged())) { : cloner(new BridgedClonerImpl(inst.unbridged())) {
context.context->notifyNewCloner();
}
BridgedCloner::BridgedCloner(BridgedFunction emptyFunction, BridgedContext context)
: cloner(new BridgedClonerImpl(*emptyFunction.getFunction())) {
context.context->notifyNewCloner(); context.context->notifyNewCloner();
} }
@@ -608,6 +645,10 @@ void BridgedCloner::destroy(BridgedContext context) {
context.context->notifyClonerDestroyed(); context.context->notifyClonerDestroyed();
} }
BridgedFunction BridgedCloner::getCloned() const {
return { &cloner->getBuilder().getFunction() };
}
BridgedValue BridgedCloner::getClonedValue(BridgedValue v) { BridgedValue BridgedCloner::getClonedValue(BridgedValue v) {
return {cloner->getClonedValue(v.getSILValue())}; return {cloner->getClonedValue(v.getSILValue())};
} }
@@ -616,12 +657,32 @@ bool BridgedCloner::isValueCloned(BridgedValue v) const {
return cloner->isValueCloned(v.getSILValue()); return cloner->isValueCloned(v.getSILValue());
} }
void BridgedCloner::clone(BridgedInstruction inst) { void BridgedCloner::recordClonedInstruction(BridgedInstruction origInst, BridgedInstruction clonedInst) const {
cloner->cloneInst(inst.unbridged()); cloner->recordClonedInstruction(origInst.unbridged(), clonedInst.unbridged());
} }
void BridgedCloner::recordFoldedValue(BridgedValue origValue, BridgedValue mappedValue) { void BridgedCloner::recordFoldedValue(BridgedValue orig, BridgedValue mapped) const {
cloner->recordFoldedValue(origValue.getSILValue(), mappedValue.getSILValue()); cloner->recordFoldedValue(orig.getSILValue(), mapped.getSILValue());
}
BridgedInstruction BridgedCloner::clone(BridgedInstruction inst) {
return {cloner->cloneInst(inst.unbridged())->asSILNode()};
}
BridgedBasicBlock BridgedCloner::getClonedBasicBlock(BridgedBasicBlock originalBasicBlock) const {
return { cloner->getOpBasicBlock(originalBasicBlock.unbridged()) };
}
void BridgedCloner::cloneFunctionBody(BridgedFunction originalFunction,
BridgedBasicBlock clonedEntryBlock,
BridgedValueArray clonedEntryBlockArgs) const {
llvm::SmallVector<swift::SILValue, 16> clonedEntryBlockArgsStorage;
auto clonedEntryBlockArgsArrayRef = clonedEntryBlockArgs.getValues(clonedEntryBlockArgsStorage);
cloner->cloneFunctionBody(originalFunction.getFunction(), clonedEntryBlock.unbridged(), clonedEntryBlockArgsArrayRef);
}
void BridgedCloner::cloneFunctionBody(BridgedFunction originalFunction) const {
cloner->cloneFunction(originalFunction.getFunction());
} }
//===----------------------------------------------------------------------===// //===----------------------------------------------------------------------===//

View File

@@ -272,32 +272,31 @@ BridgedOwnedString BridgedPassContext::mangleWithDeadArgs(BridgedArrayRef bridge
} }
BridgedOwnedString BridgedPassContext::mangleWithClosureArgs( BridgedOwnedString BridgedPassContext::mangleWithClosureArgs(
BridgedValueArray bridgedClosureArgs, BridgedArrayRef bridgedClosureArgs, BridgedFunction applySiteCallee
BridgedArrayRef bridgedClosureArgIndices,
BridgedFunction applySiteCallee
) const { ) const {
struct ClosureArgElement {
SwiftInt argIdx;
BridgeValueExistential argValue;
};
auto pass = Demangle::SpecializationPass::ClosureSpecializer; auto pass = Demangle::SpecializationPass::ClosureSpecializer;
auto serializedKind = applySiteCallee.getFunction()->getSerializedKind(); auto serializedKind = applySiteCallee.getFunction()->getSerializedKind();
Mangle::FunctionSignatureSpecializationMangler mangler(applySiteCallee.getFunction()->getASTContext(), Mangle::FunctionSignatureSpecializationMangler mangler(applySiteCallee.getFunction()->getASTContext(),
pass, serializedKind, applySiteCallee.getFunction()); pass, serializedKind, applySiteCallee.getFunction());
llvm::SmallVector<swift::SILValue, 16> closureArgsStorage; auto closureArgs = bridgedClosureArgs.unbridged<ClosureArgElement>();
auto closureArgs = bridgedClosureArgs.getValues(closureArgsStorage);
auto closureArgIndices = bridgedClosureArgIndices.unbridged<SwiftInt>();
assert(closureArgs.size() == closureArgIndices.size() && for (ClosureArgElement argElmt : closureArgs) {
"Number of closures arguments and number of closure indices do not match!"); auto closureArg = argElmt.argValue.value.getSILValue();
auto closureArgIndex = argElmt.argIdx;
for (size_t i = 0; i < closureArgs.size(); i++) {
auto closureArg = closureArgs[i];
auto closureArgIndex = closureArgIndices[i];
if (auto *PAI = dyn_cast<PartialApplyInst>(closureArg)) { if (auto *PAI = dyn_cast<PartialApplyInst>(closureArg)) {
mangler.setArgumentClosureProp(closureArgIndex, mangler.setArgumentClosureProp(closureArgIndex,
const_cast<PartialApplyInst *>(PAI)); const_cast<PartialApplyInst *>(PAI));
} else { } else {
auto *TTTFI = cast<ThinToThickFunctionInst>(closureArg); auto *TTTFI = cast<ThinToThickFunctionInst>(closureArg);
mangler.setArgumentClosureProp(closureArgIndex, mangler.setArgumentClosureProp(closureArgIndex,
const_cast<ThinToThickFunctionInst *>(TTTFI)); const_cast<ThinToThickFunctionInst *>(TTTFI));
} }
} }
@@ -459,43 +458,12 @@ BridgedCalleeAnalysis::CalleeList BridgedCalleeAnalysis::getDestructors(BridgedT
return ca->getDestructors(type.unbridged(), isExactType); return ca->getDestructors(type.unbridged(), isExactType);
} }
namespace swift {
class SpecializationCloner: public SILClonerWithScopes<SpecializationCloner> {
friend class SILInstructionVisitor<SpecializationCloner>;
friend class SILCloner<SpecializationCloner>;
public:
using SuperTy = SILClonerWithScopes<SpecializationCloner>;
SpecializationCloner(SILFunction &emptySpecializedFunction): SuperTy(emptySpecializedFunction) {}
};
} // namespace swift
BridgedSpecializationCloner::BridgedSpecializationCloner(BridgedFunction emptySpecializedFunction):
cloner(new SpecializationCloner(*emptySpecializedFunction.getFunction())) {}
BridgedFunction BridgedSpecializationCloner::getCloned() const {
return { &cloner->getBuilder().getFunction() };
}
BridgedBasicBlock BridgedSpecializationCloner::getClonedBasicBlock(BridgedBasicBlock originalBasicBlock) const {
return { cloner->getOpBasicBlock(originalBasicBlock.unbridged()) };
}
void BridgedSpecializationCloner::cloneFunctionBody(BridgedFunction originalFunction, BridgedBasicBlock clonedEntryBlock, BridgedValueArray clonedEntryBlockArgs) const {
llvm::SmallVector<swift::SILValue, 16> clonedEntryBlockArgsStorage;
auto clonedEntryBlockArgsArrayRef = clonedEntryBlockArgs.getValues(clonedEntryBlockArgsStorage);
cloner->cloneFunctionBody(originalFunction.getFunction(), clonedEntryBlock.unbridged(), clonedEntryBlockArgsArrayRef);
}
void BridgedSpecializationCloner::cloneFunctionBody(BridgedFunction originalFunction) const {
cloner->cloneFunction(originalFunction.getFunction());
}
void BridgedBuilder::destroyCapturedArgs(BridgedInstruction partialApply) const { void BridgedBuilder::destroyCapturedArgs(BridgedInstruction partialApply) const {
if (auto *pai = llvm::dyn_cast<PartialApplyInst>(partialApply.unbridged()); pai->isOnStack()) { if (auto *pai = llvm::dyn_cast<PartialApplyInst>(partialApply.unbridged()); pai->isOnStack()) {
auto b = unbridged(); auto b = unbridged();
return swift::insertDestroyOfCapturedArguments(pai, b); return swift::insertDestroyOfCapturedArguments(pai, b);
} else { } else {
assert(false && "`destroyCapturedArgs` must only be called on a `partial_apply` on stack!"); assert(false && "`destroyCapturedArgs` must only be called on a `partial_apply` on stack!");
} }
} }