diff --git a/SwiftCompilerSources/Sources/Optimizer/Analysis/AliasAnalysis.swift b/SwiftCompilerSources/Sources/Optimizer/Analysis/AliasAnalysis.swift index f1eb258c3fa49..1f74f1d8b93ac 100644 --- a/SwiftCompilerSources/Sources/Optimizer/Analysis/AliasAnalysis.swift +++ b/SwiftCompilerSources/Sources/Optimizer/Analysis/AliasAnalysis.swift @@ -15,7 +15,7 @@ import SIL extension FunctionPassContext { var aliasAnalysis: AliasAnalysis { - let bridgedAA = _bridged.getAliasAnalysis() + let bridgedAA = bridgedPassContext.getAliasAnalysis() return AliasAnalysis(bridged: bridgedAA, context: self) } } @@ -113,7 +113,7 @@ struct AliasAnalysis { bridgedAliasAnalysis.mutableCachePointer.assumingMemoryBound(to: Cache.self).deinitialize(count: 1) }, // getMemEffectsFn - { (bridgedCtxt: BridgedPassContext, + { (bridgedCtxt: BridgedContext, bridgedAliasAnalysis: BridgedAliasAnalysis, bridgedAddr: BridgedValue, bridgedInst: BridgedInstruction) -> BridgedMemoryBehavior in @@ -121,7 +121,7 @@ struct AliasAnalysis { return aa.getMemoryEffect(of: bridgedInst.instruction, on: bridgedAddr.value).bridged }, // isObjReleasedFn - { (bridgedCtxt: BridgedPassContext, + { (bridgedCtxt: BridgedContext, bridgedAliasAnalysis: BridgedAliasAnalysis, bridgedObj: BridgedValue, bridgedInst: BridgedInstruction) -> Bool in @@ -142,7 +142,7 @@ struct AliasAnalysis { }, // isAddrVisibleFromObj - { (bridgedCtxt: BridgedPassContext, + { (bridgedCtxt: BridgedContext, bridgedAliasAnalysis: BridgedAliasAnalysis, bridgedAddr: BridgedValue, bridgedObj: BridgedValue) -> Bool in @@ -159,7 +159,7 @@ struct AliasAnalysis { }, // mayAliasFn - { (bridgedCtxt: BridgedPassContext, + { (bridgedCtxt: BridgedContext, bridgedAliasAnalysis: BridgedAliasAnalysis, bridgedLhs: BridgedValue, bridgedRhs: BridgedValue) -> Bool in diff --git a/SwiftCompilerSources/Sources/Optimizer/DataStructures/CMakeLists.txt b/SwiftCompilerSources/Sources/Optimizer/DataStructures/CMakeLists.txt index 9cda577b95a84..f5e7afa317c82 100644 --- a/SwiftCompilerSources/Sources/Optimizer/DataStructures/CMakeLists.txt +++ b/SwiftCompilerSources/Sources/Optimizer/DataStructures/CMakeLists.txt @@ -7,11 +7,6 @@ # See http://swift.org/CONTRIBUTORS.txt for Swift project authors swift_compiler_sources(Optimizer - BasicBlockRange.swift DeadEndBlocks.swift FunctionUses.swift - InstructionRange.swift - ReachableBlocks.swift - Set.swift - Stack.swift - Worklist.swift) + ReachableBlocks.swift) diff --git a/SwiftCompilerSources/Sources/Optimizer/FunctionPasses/AllocBoxToStack.swift b/SwiftCompilerSources/Sources/Optimizer/FunctionPasses/AllocBoxToStack.swift index 416350b9b8d17..6856e64c23f65 100644 --- a/SwiftCompilerSources/Sources/Optimizer/FunctionPasses/AllocBoxToStack.swift +++ b/SwiftCompilerSources/Sources/Optimizer/FunctionPasses/AllocBoxToStack.swift @@ -102,7 +102,7 @@ private func tryConvertBoxesToStack(in function: Function, _ context: FunctionPa hoistMarkUnresolvedInsts(stackAddress: stack, checkKind: .consumableAndAssignable, context) } if !promotableBoxes.isEmpty { - function.fixStackNesting(context) + context.fixStackNesting(in: function) } return functionsToSpecialize diff --git a/SwiftCompilerSources/Sources/Optimizer/FunctionPasses/ClosureSpecialization.swift b/SwiftCompilerSources/Sources/Optimizer/FunctionPasses/ClosureSpecialization.swift index ff2458dfa702b..8559e8365680a 100644 --- a/SwiftCompilerSources/Sources/Optimizer/FunctionPasses/ClosureSpecialization.swift +++ b/SwiftCompilerSources/Sources/Optimizer/FunctionPasses/ClosureSpecialization.swift @@ -158,7 +158,7 @@ let autodiffClosureSpecialization = FunctionPass(name: "autodiff-closure-special } if context.needFixStackNesting { - function.fixStackNesting(context) + context.fixStackNesting(in: function) } remainingSpecializationRounds -= 1 @@ -836,7 +836,7 @@ private extension SpecializationCloner { } if (self.context.needFixStackNesting) { - self.cloned.fixStackNesting(self.context) + self.context.fixStackNesting(in: self.cloned) } } } diff --git a/SwiftCompilerSources/Sources/Optimizer/FunctionPasses/ComputeEscapeEffects.swift b/SwiftCompilerSources/Sources/Optimizer/FunctionPasses/ComputeEscapeEffects.swift index e452967c2766e..3b2ab2c5e242c 100644 --- a/SwiftCompilerSources/Sources/Optimizer/FunctionPasses/ComputeEscapeEffects.swift +++ b/SwiftCompilerSources/Sources/Optimizer/FunctionPasses/ComputeEscapeEffects.swift @@ -72,7 +72,7 @@ let computeEscapeEffects = FunctionPass(name: "compute-escape-effects") { return } - context.modifyEffects(in: function) { (effects: inout FunctionEffects) in + function.modifyEffects(context) { (effects: inout FunctionEffects) in effects.escapeEffects.arguments = newEffects } } diff --git a/SwiftCompilerSources/Sources/Optimizer/FunctionPasses/ComputeSideEffects.swift b/SwiftCompilerSources/Sources/Optimizer/FunctionPasses/ComputeSideEffects.swift index ce60db6ba195f..427c599a1fd0d 100644 --- a/SwiftCompilerSources/Sources/Optimizer/FunctionPasses/ComputeSideEffects.swift +++ b/SwiftCompilerSources/Sources/Optimizer/FunctionPasses/ComputeSideEffects.swift @@ -69,7 +69,7 @@ let computeSideEffects = FunctionPass(name: "compute-side-effects") { } // Finally replace the function's side effects. - context.modifyEffects(in: function) { (effects: inout FunctionEffects) in + function.modifyEffects(context) { (effects: inout FunctionEffects) in let globalEffects = function.isProgramTerminationPoint ? collectedEffects.globalEffects.forProgramTerminationPoints : collectedEffects.globalEffects diff --git a/SwiftCompilerSources/Sources/Optimizer/FunctionPasses/SimplificationPasses.swift b/SwiftCompilerSources/Sources/Optimizer/FunctionPasses/SimplificationPasses.swift index 678024ac9c9c2..07b0cac69f05f 100644 --- a/SwiftCompilerSources/Sources/Optimizer/FunctionPasses/SimplificationPasses.swift +++ b/SwiftCompilerSources/Sources/Optimizer/FunctionPasses/SimplificationPasses.swift @@ -110,7 +110,7 @@ func runSimplification(on function: Function, _ context: FunctionPassContext, } while !worklist.isEmpty if context.needFixStackNesting { - function.fixStackNesting(context) + context.fixStackNesting(in: function) } return changed diff --git a/SwiftCompilerSources/Sources/Optimizer/FunctionPasses/StackPromotion.swift b/SwiftCompilerSources/Sources/Optimizer/FunctionPasses/StackPromotion.swift index 2d0fe05b96f38..7d522eade4bb5 100644 --- a/SwiftCompilerSources/Sources/Optimizer/FunctionPasses/StackPromotion.swift +++ b/SwiftCompilerSources/Sources/Optimizer/FunctionPasses/StackPromotion.swift @@ -57,7 +57,7 @@ let stackPromotion = FunctionPass(name: "stack-promotion") { } if needFixStackNesting { // Make sure that all stack allocating instructions are nested correctly. - function.fixStackNesting(context) + context.fixStackNesting(in: function) } } diff --git a/SwiftCompilerSources/Sources/Optimizer/InstructionSimplification/SimplifyBuiltin.swift b/SwiftCompilerSources/Sources/Optimizer/InstructionSimplification/SimplifyBuiltin.swift index b7fb3a4244b79..dca616d2e2e1c 100644 --- a/SwiftCompilerSources/Sources/Optimizer/InstructionSimplification/SimplifyBuiltin.swift +++ b/SwiftCompilerSources/Sources/Optimizer/InstructionSimplification/SimplifyBuiltin.swift @@ -56,7 +56,7 @@ extension BuiltinInst : OnoneSimplifiable, SILCombineSimplifiable { case .Xor: simplifyNegation(context) default: - if let literal = constantFold(context) { + if let literal = context.constantFold(builtin: self) { uses.replaceAll(with: literal, context) } } @@ -240,7 +240,7 @@ private extension BuiltinInst { if constantFoldStringNullPointerCheck(isEqual: isEqual, context) { return } - if let literal = constantFold(context) { + if let literal = context.constantFold(builtin: self) { uses.replaceAll(with: literal, context) } } diff --git a/SwiftCompilerSources/Sources/Optimizer/ModulePasses/StackProtection.swift b/SwiftCompilerSources/Sources/Optimizer/ModulePasses/StackProtection.swift index 3c82c874bf3ad..ba24846817d41 100644 --- a/SwiftCompilerSources/Sources/Optimizer/ModulePasses/StackProtection.swift +++ b/SwiftCompilerSources/Sources/Optimizer/ModulePasses/StackProtection.swift @@ -113,7 +113,7 @@ private struct StackProtectionOptimization { process(instruction: inst, in: function, mustFixStackNesting: &mustFixStackNesting, context) } if mustFixStackNesting { - function.fixStackNesting(context) + context.fixStackNesting(in: function) } } diff --git a/SwiftCompilerSources/Sources/Optimizer/PassManager/CMakeLists.txt b/SwiftCompilerSources/Sources/Optimizer/PassManager/CMakeLists.txt index a1da2f6e96fa4..4a46ced58a617 100644 --- a/SwiftCompilerSources/Sources/Optimizer/PassManager/CMakeLists.txt +++ b/SwiftCompilerSources/Sources/Optimizer/PassManager/CMakeLists.txt @@ -7,9 +7,10 @@ # See http://swift.org/CONTRIBUTORS.txt for Swift project authors swift_compiler_sources(Optimizer - Context.swift + ContextCommon.swift + FunctionPassContext.swift ModulePassContext.swift Options.swift Passes.swift - PassRegistration.swift) - + PassRegistration.swift + SimplifyContext.swift) diff --git a/SwiftCompilerSources/Sources/Optimizer/PassManager/Context.swift b/SwiftCompilerSources/Sources/Optimizer/PassManager/Context.swift deleted file mode 100644 index 393960e6329f5..0000000000000 --- a/SwiftCompilerSources/Sources/Optimizer/PassManager/Context.swift +++ /dev/null @@ -1,859 +0,0 @@ -//===--- 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 - -/// The base type of all contexts. -protocol Context { - var _bridged: BridgedPassContext { get } -} - -extension Context { - var options: Options { Options(_bridged: _bridged) } - - var diagnosticEngine: DiagnosticEngine { - return DiagnosticEngine(bridged: _bridged.getDiagnosticEngine()) - } - - // The calleeAnalysis is not specific to a function and therefore can be provided in - // all contexts. - var calleeAnalysis: CalleeAnalysis { - let bridgeCA = _bridged.getCalleeAnalysis() - return CalleeAnalysis(bridged: bridgeCA) - } - - var hadError: Bool { _bridged.hadError() } - - var silStage: SILStage { - switch _bridged.getSILStage() { - case .Raw: return .raw - case .Canonical: return .canonical - case .Lowered: return .lowered - default: fatalError("unhandled SILStage case") - } - } - - var currentModuleContext: ModuleDecl { - _bridged.getCurrentModuleContext().getAs(ModuleDecl.self) - } - - var moduleIsSerialized: Bool { _bridged.moduleIsSerialized() } - - var moduleHasLoweredAddresses: Bool { _bridged.moduleHasLoweredAddresses() } - - /// 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 { - _bridged.enableWMORequiredDiagnostics() - } - - func canMakeStaticObjectReadOnly(objectType: Type) -> Bool { - _bridged.canMakeStaticObjectReadOnly(objectType.bridged) - } - - func lookupDeinit(ofNominal: NominalTypeDecl) -> Function? { - _bridged.lookUpNominalDeinitFunction(ofNominal.bridged).function - } - - func getBuiltinIntegerType(bitWidth: Int) -> Type { _bridged.getBuiltinIntegerType(bitWidth).type } - - func lookupFunction(name: String) -> Function? { - name._withBridgedStringRef { - _bridged.lookupFunction($0).function - } - } - - func lookupWitnessTable(for conformance: Conformance) -> WitnessTable? { - return _bridged.lookupWitnessTable(conformance.bridged).witnessTable - } - - func lookupVTable(for classDecl: NominalTypeDecl) -> VTable? { - return _bridged.lookupVTable(classDecl.bridged).vTable - } - - func lookupSpecializedVTable(for classType: Type) -> VTable? { - return _bridged.lookupSpecializedVTable(classType.bridged).vTable - } - - func getSpecializedConformance(of genericConformance: Conformance, - for type: AST.`Type`, - substitutions: SubstitutionMap) -> Conformance - { - let c = _bridged.getSpecializedConformance(genericConformance.bridged, type.bridged, substitutions.bridged) - return Conformance(bridged: c) - } - - func notifyNewFunction(function: Function, derivedFrom: Function) { - _bridged.addFunctionToPassManagerWorklist(function.bridged, derivedFrom.bridged) - } -} - -/// A context which allows mutation of a function's SIL. -protocol MutatingContext : Context { - // Called by all instruction mutations, including inserted new instructions. - var notifyInstructionChanged: (Instruction) -> () { get } -} - -extension MutatingContext { - func notifyInvalidatedStackNesting() { _bridged.notifyInvalidatedStackNesting() } - var needFixStackNesting: Bool { _bridged.getNeedFixStackNesting() } - - func verifyIsTransforming(function: Function) { - precondition(_bridged.isTransforming(function.bridged), "pass modifies wrong function") - } - - /// Splits the basic block, which contains `inst`, before `inst` and returns the - /// new block. - /// - /// `inst` and all subsequent instructions are moved to the new block, while all - /// instructions _before_ `inst` remain in the original block. - func splitBlock(before inst: Instruction) -> BasicBlock { - notifyBranchesChanged() - return _bridged.splitBlockBefore(inst.bridged).block - } - - /// Splits the basic block, which contains `inst`, after `inst` and returns the - /// new block. - /// - /// All subsequent instructions after `inst` are moved to the new block, while `inst` and all - /// instructions _before_ `inst` remain in the original block. - func splitBlock(after inst: Instruction) -> BasicBlock { - notifyBranchesChanged() - return _bridged.splitBlockAfter(inst.bridged).block - } - - func createBlock(after block: BasicBlock) -> BasicBlock { - notifyBranchesChanged() - return _bridged.createBlockAfter(block.bridged).block - } - - /// Removes and deletes `instruction`. - /// If `salvageDebugInfo` is true, compensating `debug_value` instructions are inserted for certain - /// kind of instructions. - func erase(instruction: Instruction, salvageDebugInfo: Bool = true) { - if !instruction.isInStaticInitializer { - verifyIsTransforming(function: instruction.parentFunction) - } - if instruction is FullApplySite { - notifyCallsChanged() - } - if instruction is TermInst { - notifyBranchesChanged() - } - notifyInstructionsChanged() - - _bridged.eraseInstruction(instruction.bridged, salvageDebugInfo) - } - - func erase(instructionIncludingAllUsers inst: Instruction) { - if inst.isDeleted { - return - } - for result in inst.results { - for use in result.uses { - erase(instructionIncludingAllUsers: use.instruction) - } - } - // We rely that after deleting the instruction its operands have no users. - // Therefore `salvageDebugInfo` must be turned off because we cannot insert debug_value instructions. - erase(instruction: inst, salvageDebugInfo: false) - } - - func erase(instructions: S) where S.Element: Instruction { - for inst in instructions { - erase(instruction: inst) - } - } - - func erase(instructionIncludingDebugUses inst: Instruction) { - precondition(inst.results.allSatisfy { $0.uses.ignoreDebugUses.isEmpty }) - erase(instructionIncludingAllUsers: inst) - } - - func erase(block: BasicBlock) { - _bridged.eraseBlock(block.bridged) - } - - func tryOptimizeApplyOfPartialApply(closure: PartialApplyInst) -> Bool { - if _bridged.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 _bridged.tryDeleteDeadClosure(closure.bridged, needKeepArgsAlive) { - notifyInstructionsChanged() - return true - } - return false - } - - func tryDevirtualize(apply: FullApplySite, isMandatory: Bool) -> ApplySite? { - let result = _bridged.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 _bridged.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 - } - - _bridged.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)) - } - - func notifyInstructionsChanged() { - _bridged.asNotificationHandler().notifyChanges(.instructionsChanged) - } - - func notifyCallsChanged() { - _bridged.asNotificationHandler().notifyChanges(.callsChanged) - } - - func notifyBranchesChanged() { - _bridged.asNotificationHandler().notifyChanges(.branchesChanged) - } - - /// 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) { - _bridged.notifyDependencyOnBodyOf(otherFunction.bridged) - } -} - -/// The context which is passed to the run-function of a FunctionPass. -struct FunctionPassContext : MutatingContext { - let _bridged: BridgedPassContext - - // A no-op. - var notifyInstructionChanged: (Instruction) -> () { return { inst in } } - - func continueWithNextSubpassRun(for inst: Instruction? = nil) -> Bool { - return _bridged.continueWithNextSubpassRun(inst.bridged) - } - - func createSimplifyContext(preserveDebugInfo: Bool, notifyInstructionChanged: @escaping (Instruction) -> ()) -> SimplifyContext { - SimplifyContext(_bridged: _bridged, notifyInstructionChanged: notifyInstructionChanged, preserveDebugInfo: preserveDebugInfo) - } - - var deadEndBlocks: DeadEndBlocksAnalysis { - let bridgeDEA = _bridged.getDeadEndBlocksAnalysis() - return DeadEndBlocksAnalysis(bridged: bridgeDEA) - } - - var dominatorTree: DominatorTree { - let bridgedDT = _bridged.getDomTree() - return DominatorTree(bridged: bridgedDT) - } - - var postDominatorTree: PostDominatorTree { - let bridgedPDT = _bridged.getPostDomTree() - return PostDominatorTree(bridged: bridgedPDT) - } - - var swiftArrayDecl: NominalTypeDecl { - _bridged.getSwiftArrayDecl().getAs(NominalTypeDecl.self) - } - - var swiftMutableSpan: NominalTypeDecl { - _bridged.getSwiftMutableSpanDecl().getAs(NominalTypeDecl.self) - } - - func loadFunction(name: StaticString, loadCalleesRecursively: Bool) -> Function? { - return name.withUTF8Buffer { (nameBuffer: UnsafeBufferPointer) in - let nameStr = BridgedStringRef(data: nameBuffer.baseAddress, count: nameBuffer.count) - return _bridged.loadFunction(nameStr, loadCalleesRecursively).function - } - } - - /// Looks up a function in the `Swift` module. - /// The `name` is the source name of the function and not the mangled name. - /// Returns nil if no such function or multiple matching functions are found. - func lookupStdlibFunction(name: StaticString) -> Function? { - return name.withUTF8Buffer { (nameBuffer: UnsafeBufferPointer) in - let nameStr = BridgedStringRef(data: nameBuffer.baseAddress, count: nameBuffer.count) - return _bridged.lookupStdlibFunction(nameStr).function - } - } - - func modifyEffects(in function: Function, _ body: (inout FunctionEffects) -> ()) { - notifyEffectsChanged() - function._modifyEffects(body) - } - - fileprivate func notifyEffectsChanged() { - _bridged.asNotificationHandler().notifyChanges(.effectsChanged) - } - - func eliminateDeadAllocations(in function: Function) -> Bool { - if _bridged.eliminateDeadAllocations(function.bridged) { - notifyInstructionsChanged() - return true - } - return false - } - - func specializeClassMethodInst(_ cm: ClassMethodInst) -> Bool { - if _bridged.specializeClassMethodInst(cm.bridged) { - notifyInstructionsChanged() - notifyCallsChanged() - return true - } - return false - } - - func specializeWitnessMethodInst(_ wm: WitnessMethodInst) -> Bool { - if _bridged.specializeWitnessMethodInst(wm.bridged) { - notifyInstructionsChanged() - notifyCallsChanged() - return true - } - return false - } - - func specializeApplies(in function: Function, isMandatory: Bool) -> Bool { - if _bridged.specializeAppliesInFunction(function.bridged, isMandatory) { - notifyInstructionsChanged() - notifyCallsChanged() - return true - } - return false - } - - func mangleOutlinedVariable(from function: Function) -> String { - return String(taking: _bridged.mangleOutlinedVariable(function.bridged)) - } - - func mangle(withClosureArguments closureArgs: [Value], closureArgIndices: [Int], from applySiteCallee: Function) -> String { - closureArgs.withBridgedValues { bridgedClosureArgsRef in - closureArgIndices.withBridgedArrayRef{bridgedClosureArgIndicesRef in - String(taking: _bridged.mangleWithClosureArgs( - bridgedClosureArgsRef, - bridgedClosureArgIndicesRef, - applySiteCallee.bridged - )) - } - } - } - - func mangle(withBoxToStackPromotedArguments argIndices: [Int], from original: Function) -> String { - argIndices.withBridgedArrayRef { bridgedArgIndices in - String(taking: _bridged.mangleWithBoxToStackPromotedArgs(bridgedArgIndices, original.bridged)) - } - } - - func createGlobalVariable(name: String, type: Type, linkage: Linkage, isLet: Bool) -> GlobalVariable { - let gv = name._withBridgedStringRef { - _bridged.createGlobalVariable($0, type.bridged, linkage.bridged, isLet) - } - return gv.globalVar - } - - 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 - _bridged.createSpecializedFunctionDeclaration(nameRef, paramBuf.baseAddress, paramBuf.count, - original.bridged, makeThin, makeBare).function - } - } - } - - func buildSpecializedFunction(specializedFunction: Function, buildFn: (Function, FunctionPassContext) -> T) -> T { - let nestedFunctionPassContext = - FunctionPassContext(_bridged: _bridged.initializeNestedPassContext(specializedFunction.bridged)) - - defer { _bridged.deinitializedNestedPassContext() } - - return buildFn(specializedFunction, nestedFunctionPassContext) - } - - /// 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 _bridged.completeLifetime(value.bridged) { - notifyInstructionsChanged() - } - } -} - -struct SimplifyContext : MutatingContext { - let _bridged: BridgedPassContext - let notifyInstructionChanged: (Instruction) -> () - let preserveDebugInfo: Bool -} - -extension Type { - func getStaticSize(context: SimplifyContext) -> Int? { - let v = context._bridged.getStaticSize(self.bridged) - return v == -1 ? nil : v - } - - func getStaticAlignment(context: SimplifyContext) -> Int? { - let v = context._bridged.getStaticAlignment(self.bridged) - return v == -1 ? nil : v - } - - func getStaticStride(context: SimplifyContext) -> Int? { - let v = context._bridged.getStaticStride(self.bridged) - return v == -1 ? nil : v - } -} - -//===----------------------------------------------------------------------===// -// Builder initialization -//===----------------------------------------------------------------------===// - -private extension Instruction { - /// Returns self, unless self is a meta instruction, in which case the next - /// non-meta instruction is returned. Returns nil if there are no non-meta - /// instructions in the basic block. - var nextNonMetaInstruction: Instruction? { - for inst in InstructionList(first: self) where !(inst is MetaInstruction) { - return inst - } - return nil - } -} - -extension Builder { - /// Creates a builder which inserts _before_ `insPnt`, using a custom `location`. - init(before insPnt: Instruction, location: Location, _ context: some MutatingContext) { - context.verifyIsTransforming(function: insPnt.parentFunction) - self.init(insertAt: .before(insPnt), location: location, - context.notifyInstructionChanged, context._bridged.asNotificationHandler()) - } - - /// Creates a builder which inserts before `insPnt`, using `insPnt`'s next - /// non-meta instruction's location. - /// This function should be used when moving code to an unknown insert point, - /// when we want to inherit the location of the closest non-meta instruction. - /// For replacing an existing meta instruction with another, use - /// ``Builder.init(replacing:_:)``. - init(before insPnt: Instruction, _ context: some MutatingContext) { - context.verifyIsTransforming(function: insPnt.parentFunction) - self.init(insertAt: .before(insPnt), - location: insPnt.location, - context.notifyInstructionChanged, context._bridged.asNotificationHandler()) - } - - /// Creates a builder which inserts _before_ `insPnt`, using the exact location of `insPnt`, - /// for the purpose of replacing that meta instruction with an equivalent instruction. - /// This function does not delete `insPnt`. - init(replacing insPnt: MetaInstruction, _ context: some MutatingContext) { - context.verifyIsTransforming(function: insPnt.parentFunction) - self.init(insertAt: .before(insPnt), location: insPnt.location, - context.notifyInstructionChanged, context._bridged.asNotificationHandler()) - } - - /// Creates a builder which inserts _after_ `insPnt`, using a custom `location`. - /// - /// TODO: this is usually incorrect for terminator instructions. Instead use - /// `Builder.insert(after:location:_:insertFunc)` from OptUtils.swift. Rename this to afterNonTerminator. - init(after insPnt: Instruction, location: Location, _ context: some MutatingContext) { - context.verifyIsTransforming(function: insPnt.parentFunction) - guard let nextInst = insPnt.next else { - fatalError("cannot insert an instruction after a block terminator.") - } - self.init(insertAt: .before(nextInst), location: location, - context.notifyInstructionChanged, context._bridged.asNotificationHandler()) - } - - /// Creates a builder which inserts _after_ `insPnt`, using `insPnt`'s next - /// non-meta instruction's location. - /// - /// TODO: this is incorrect for terminator instructions. Instead use `Builder.insert(after:location:_:insertFunc)` - /// from OptUtils.swift. Rename this to afterNonTerminator. - init(after insPnt: Instruction, _ context: some MutatingContext) { - self.init(after: insPnt, location: insPnt.location, context) - } - - /// Creates a builder which inserts at the end of `block`, using a custom `location`. - init(atEndOf block: BasicBlock, location: Location, _ context: some MutatingContext) { - context.verifyIsTransforming(function: block.parentFunction) - self.init(insertAt: .atEndOf(block), location: location, - context.notifyInstructionChanged, context._bridged.asNotificationHandler()) - } - - /// Creates a builder which inserts at the begin of `block`, using a custom `location`. - init(atBeginOf block: BasicBlock, location: Location, _ context: some MutatingContext) { - context.verifyIsTransforming(function: block.parentFunction) - let firstInst = block.instructions.first! - self.init(insertAt: .before(firstInst), location: location, - context.notifyInstructionChanged, context._bridged.asNotificationHandler()) - } - - /// Creates a builder which inserts at the begin of `block`, using the location of the first - /// non-meta instruction of `block`. - init(atBeginOf block: BasicBlock, _ context: some MutatingContext) { - context.verifyIsTransforming(function: block.parentFunction) - let firstInst = block.instructions.first! - self.init(insertAt: .before(firstInst), - location: firstInst.location, - context.notifyInstructionChanged, context._bridged.asNotificationHandler()) - } - - /// Creates a builder which inserts instructions into an empty function, using the location of the function itself. - init(atStartOf function: Function, _ context: some MutatingContext) { - context.verifyIsTransforming(function: function) - self.init(insertAt: .atStartOf(function), location: function.location, - context.notifyInstructionChanged, context._bridged.asNotificationHandler()) - } - - init(staticInitializerOf global: GlobalVariable, _ context: some MutatingContext) { - self.init(insertAt: .staticInitializer(global), - location: Location.artificialUnreachableLocation, - { _ in }, context._bridged.asNotificationHandler()) - } -} - -//===----------------------------------------------------------------------===// -// Modifying the SIL -//===----------------------------------------------------------------------===// - -extension Undef { - static func get(type: Type, _ context: some MutatingContext) -> Undef { - context._bridged.getSILUndef(type.bridged).value as! Undef - } -} - -extension BasicBlock { - func addArgument(type: Type, ownership: Ownership, _ context: some MutatingContext) -> Argument { - context.notifyInstructionsChanged() - return bridged.addBlockArgument(type.bridged, ownership._bridged).argument - } - - func addFunctionArgument(type: Type, _ context: some MutatingContext) -> FunctionArgument { - context.notifyInstructionsChanged() - return bridged.addFunctionArgument(type.bridged).argument as! FunctionArgument - } - - func insertFunctionArgument(atPosition: Int, type: Type, ownership: Ownership, decl: ValueDecl? = nil, - _ context: some MutatingContext) -> FunctionArgument - { - context.notifyInstructionsChanged() - return bridged.insertFunctionArgument(atPosition, type.bridged, ownership._bridged, - (decl as Decl?).bridged).argument as! FunctionArgument - } - - func eraseArgument(at index: Int, _ context: some MutatingContext) { - context.notifyInstructionsChanged() - bridged.eraseArgument(index) - } - - func moveAllInstructions(toBeginOf otherBlock: BasicBlock, _ context: some MutatingContext) { - context.notifyInstructionsChanged() - context.notifyBranchesChanged() - bridged.moveAllInstructionsToBegin(otherBlock.bridged) - } - - func moveAllInstructions(toEndOf otherBlock: BasicBlock, _ context: some MutatingContext) { - context.notifyInstructionsChanged() - context.notifyBranchesChanged() - bridged.moveAllInstructionsToEnd(otherBlock.bridged) - } - - func eraseAllArguments(_ context: some MutatingContext) { - // Arguments are stored in an array. We need to erase in reverse order to avoid quadratic complexity. - for argIdx in (0 ..< arguments.count).reversed() { - eraseArgument(at: argIdx, context) - } - } - - func moveAllArguments(to otherBlock: BasicBlock, _ context: some MutatingContext) { - bridged.moveArgumentsTo(otherBlock.bridged) - } -} - -extension Argument { - func set(reborrow: Bool, _ context: some MutatingContext) { - context.notifyInstructionsChanged() - bridged.setReborrow(reborrow) - } -} - -extension FunctionArgument { - /// Copies the following flags from `arg`: - /// 1. noImplicitCopy - /// 2. lifetimeAnnotation - /// 3. closureCapture - /// 4. parameterPack - func copyFlags(from arg: FunctionArgument, _ context: some MutatingContext) { - context.notifyInstructionsChanged() - bridged.copyFlags(arg.bridged) - } -} - -extension AllocRefInstBase { - func setIsStackAllocatable(_ context: some MutatingContext) { - context.notifyInstructionsChanged() - bridged.AllocRefInstBase_setIsStackAllocatable() - context.notifyInstructionChanged(self) - } -} - -extension Sequence where Element == Operand { - func replaceAll(with replacement: Value, _ context: some MutatingContext) { - for use in self { - use.set(to: replacement, context) - } - } -} - -extension Operand { - func set(to value: Value, _ context: some MutatingContext) { - instruction.setOperand(at: index, to: value, context) - } - - func changeOwnership(from: Ownership, to: Ownership, _ context: some MutatingContext) { - context.notifyInstructionsChanged() - bridged.changeOwnership(from._bridged, to._bridged) - context.notifyInstructionChanged(instruction) - } -} - -extension Instruction { - func setOperand(at index : Int, to value: Value, _ context: some MutatingContext) { - if let apply = self as? FullApplySite, apply.isCallee(operand: operands[index]) { - context.notifyCallsChanged() - } - context.notifyInstructionsChanged() - bridged.setOperand(index, value.bridged) - context.notifyInstructionChanged(self) - } - - func move(before otherInstruction: Instruction, _ context: some MutatingContext) { - BridgedPassContext.moveInstructionBefore(bridged, otherInstruction.bridged) - context.notifyInstructionsChanged() - } -} - -extension BuiltinInst { - func constantFold(_ context: some MutatingContext) -> Value? { - context._bridged.constantFoldBuiltin(bridged).value - } -} - -extension RefCountingInst { - func setAtomicity(isAtomic: Bool, _ context: some MutatingContext) { - context.notifyInstructionsChanged() - bridged.RefCountingInst_setIsAtomic(isAtomic) - context.notifyInstructionChanged(self) - } -} - -extension AllocRefInst { - func setIsBare(_ context: some MutatingContext) { - context.notifyInstructionsChanged() - bridged.AllocRefInst_setIsBare() - context.notifyInstructionChanged(self) - } -} - -extension RefElementAddrInst { - func set(isImmutable: Bool, _ context: some MutatingContext) { - context.notifyInstructionsChanged() - bridged.RefElementAddrInst_setImmutable(isImmutable) - context.notifyInstructionChanged(self) - } -} - -extension GlobalAddrInst { - func clearToken(_ context: some MutatingContext) { - context.notifyInstructionsChanged() - bridged.GlobalAddrInst_clearToken() - context.notifyInstructionChanged(self) - } -} - -extension GlobalValueInst { - func setIsBare(_ context: some MutatingContext) { - context.notifyInstructionsChanged() - bridged.GlobalValueInst_setIsBare() - context.notifyInstructionChanged(self) - } -} - -extension LoadInst { - func set(ownership: LoadInst.LoadOwnership, _ context: some MutatingContext) { - context.notifyInstructionsChanged() - bridged.LoadInst_setOwnership(ownership.rawValue) - context.notifyInstructionChanged(self) - } -} - -extension PointerToAddressInst { - func set(alignment: Int?, _ context: some MutatingContext) { - context.notifyInstructionsChanged() - bridged.PointerToAddressInst_setAlignment(UInt64(alignment ?? 0)) - context.notifyInstructionChanged(self) - } -} - -extension CopyAddrInst { - func set(isTakeOfSource: Bool, _ context: some MutatingContext) { - context.notifyInstructionsChanged() - bridged.CopyAddrInst_setIsTakeOfSrc(isTakeOfSource) - context.notifyInstructionChanged(self) - } - - func set(isInitializationOfDestination: Bool, _ context: some MutatingContext) { - context.notifyInstructionsChanged() - bridged.CopyAddrInst_setIsInitializationOfDest(isInitializationOfDestination) - context.notifyInstructionChanged(self) - } -} - -extension MarkDependenceInstruction { - func resolveToNonEscaping(_ context: some MutatingContext) { - context.notifyInstructionsChanged() - bridged.MarkDependenceInstruction_resolveToNonEscaping() - context.notifyInstructionChanged(self) - } - - func settleToEscaping(_ context: some MutatingContext) { - context.notifyInstructionsChanged() - bridged.MarkDependenceInstruction_settleToEscaping() - context.notifyInstructionChanged(self) - } -} - -extension BeginAccessInst { - func set(accessKind: BeginAccessInst.AccessKind, context: some MutatingContext) { - context.notifyInstructionsChanged() - bridged.BeginAccess_setAccessKind(accessKind.rawValue) - context.notifyInstructionChanged(self) - } -} - -extension TermInst { - func replaceBranchTarget(from fromBlock: BasicBlock, to toBlock: BasicBlock, _ context: some MutatingContext) { - context.notifyBranchesChanged() - bridged.TermInst_replaceBranchTarget(fromBlock.bridged, toBlock.bridged) - } -} - -extension ForwardingInstruction { - func setForwardingOwnership(to ownership: Ownership, _ context: some MutatingContext) { - context.notifyInstructionsChanged() - bridged.ForwardingInst_setForwardingOwnership(ownership._bridged) - } -} - -extension Function { - func set(needStackProtection: Bool, _ context: FunctionPassContext) { - context.notifyEffectsChanged() - bridged.setNeedStackProtection(needStackProtection) - } - - func set(thunkKind: ThunkKind, _ context: FunctionPassContext) { - context.notifyEffectsChanged() - switch thunkKind { - case .noThunk: bridged.setThunk(.IsNotThunk) - case .thunk: bridged.setThunk(.IsThunk) - case .reabstractionThunk: bridged.setThunk(.IsReabstractionThunk) - case .signatureOptimizedThunk: bridged.setThunk(.IsSignatureOptimizedThunk) - } - } - - func set(isPerformanceConstraint: Bool, _ context: FunctionPassContext) { - context.notifyEffectsChanged() - bridged.setIsPerformanceConstraint(isPerformanceConstraint) - } - - func fixStackNesting(_ context: FunctionPassContext) { - context._bridged.fixStackNesting(bridged) - } - - func appendNewBlock(_ context: FunctionPassContext) -> BasicBlock { - context.notifyBranchesChanged() - return context._bridged.appendBlock(bridged).block - } -} - -extension DeclRef { - func calleesAreStaticallyKnowable(_ context: some Context) -> Bool { - context._bridged.calleesAreStaticallyKnowable(bridged) - } -} diff --git a/SwiftCompilerSources/Sources/Optimizer/PassManager/ContextCommon.swift b/SwiftCompilerSources/Sources/Optimizer/PassManager/ContextCommon.swift new file mode 100644 index 0000000000000..51eff5c8ce598 --- /dev/null +++ b/SwiftCompilerSources/Sources/Optimizer/PassManager/ContextCommon.swift @@ -0,0 +1,154 @@ +//===--- 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) + } +} diff --git a/SwiftCompilerSources/Sources/Optimizer/PassManager/FunctionPassContext.swift b/SwiftCompilerSources/Sources/Optimizer/PassManager/FunctionPassContext.swift new file mode 100644 index 0000000000000..18620eea7e914 --- /dev/null +++ b/SwiftCompilerSources/Sources/Optimizer/PassManager/FunctionPassContext.swift @@ -0,0 +1,147 @@ +//===--- FunctionPassContext.swift ----------------------------------------===// +// +// This source file is part of the Swift.org open source project +// +// Copyright (c) 2014 - 2025 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 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) 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(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) + } +} diff --git a/SwiftCompilerSources/Sources/Optimizer/PassManager/ModulePassContext.swift b/SwiftCompilerSources/Sources/Optimizer/PassManager/ModulePassContext.swift index 8492af42b4cae..bded40fe51ceb 100644 --- a/SwiftCompilerSources/Sources/Optimizer/PassManager/ModulePassContext.swift +++ b/SwiftCompilerSources/Sources/Optimizer/PassManager/ModulePassContext.swift @@ -20,7 +20,7 @@ import OptimizerBridging /// 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 + let _bridged: BridgedContext var description: String { return String(taking: _bridged.getModuleDescription()) @@ -95,21 +95,21 @@ struct ModulePassContext : Context, CustomStringConvertible { } var functions: FunctionList { - FunctionList(first: _bridged.getFirstFunctionInModule().function) + FunctionList(first: bridgedPassContext.getFirstFunctionInModule().function) } var globalVariables: GlobalVariableList { - GlobalVariableList(first: _bridged.getFirstGlobalInModule().globalVar) + GlobalVariableList(first: bridgedPassContext.getFirstGlobalInModule().globalVar) } - var vTables: VTableArray { VTableArray(bridgedCtxt: _bridged) } + var vTables: VTableArray { VTableArray(bridgedCtxt: bridgedPassContext) } var witnessTables: WitnessTableList { - WitnessTableList(first: _bridged.getFirstWitnessTableInModule().witnessTable) + WitnessTableList(first: bridgedPassContext.getFirstWitnessTableInModule().witnessTable) } var defaultWitnessTables: DefaultWitnessTableList { - DefaultWitnessTableList(first: _bridged.getFirstDefaultWitnessTableInModule().defaultWitnessTable) + DefaultWitnessTableList(first: bridgedPassContext.getFirstDefaultWitnessTableInModule().defaultWitnessTable) } /// Run a closure with a `PassContext` for a function, which allows to modify that function. @@ -117,9 +117,10 @@ struct ModulePassContext : Context, CustomStringConvertible { /// 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(); + let nestedBridgedContext = bridgedPassContext.initializeNestedPassContext(function.bridged) + let nestedContext = FunctionPassContext(_bridged: nestedBridgedContext) + runOnFunction(nestedContext) + bridgedPassContext.deinitializedNestedPassContext() } func loadFunction(function: Function, loadCalleesRecursively: Bool) -> Bool { @@ -131,7 +132,7 @@ struct ModulePassContext : Context, CustomStringConvertible { } func specialize(function: Function, for substitutions: SubstitutionMap) -> Function? { - return _bridged.specializeFunction(function.bridged, substitutions.bridged).function + return bridgedPassContext.specializeFunction(function.bridged, substitutions.bridged).function } enum DeserializationMode { @@ -140,7 +141,7 @@ struct ModulePassContext : Context, CustomStringConvertible { } func deserializeAllCallees(of function: Function, mode: DeserializationMode) { - _bridged.deserializeAllCallees(function.bridged, mode == .allFunctions ? true : false) + bridgedPassContext.deserializeAllCallees(function.bridged, mode == .allFunctions ? true : false) } @discardableResult @@ -197,21 +198,21 @@ struct ModulePassContext : Context, CustomStringConvertible { } func mangleAsyncRemoved(from function: Function) -> String { - return String(taking: _bridged.mangleAsyncRemoved(function.bridged)) + return String(taking: bridgedPassContext.mangleAsyncRemoved(function.bridged)) } func mangle(withDeadArguments: [Int], from function: Function) -> String { withDeadArguments.withBridgedArrayRef { bridgedArgIndices in - String(taking: _bridged.mangleWithDeadArgs(bridgedArgIndices, function.bridged)) + String(taking: bridgedPassContext.mangleWithDeadArgs(bridgedArgIndices, function.bridged)) } } func erase(function: Function) { - _bridged.eraseFunction(function.bridged) + bridgedPassContext.eraseFunction(function.bridged) } func notifyFunctionTablesChanged() { - _bridged.asNotificationHandler().notifyChanges(.functionTablesChanged) + _bridged.notifyChanges(.FunctionTables) } } diff --git a/SwiftCompilerSources/Sources/Optimizer/PassManager/PassRegistration.swift b/SwiftCompilerSources/Sources/Optimizer/PassManager/PassRegistration.swift index dc6ed6acea1b5..c89f350c7b80d 100644 --- a/SwiftCompilerSources/Sources/Optimizer/PassManager/PassRegistration.swift +++ b/SwiftCompilerSources/Sources/Optimizer/PassManager/PassRegistration.swift @@ -17,16 +17,15 @@ import OptimizerBridging @_cdecl("initializeSwiftModules") public func initializeSwiftModules() { registerAST() - registerSILClasses() + registerSIL() registerSwiftAnalyses() - registerUtilities() registerSwiftPasses() registerOptimizerTests() } private func registerPass( _ pass: ModulePass, - _ runFn: @escaping (@convention(c) (BridgedPassContext) -> ())) { + _ runFn: @escaping (@convention(c) (BridgedContext) -> ())) { pass.name._withBridgedStringRef { nameStr in SILPassManager_registerModulePass(nameStr, runFn) } @@ -158,8 +157,3 @@ private func registerSwiftAnalyses() { AliasAnalysis.register() CalleeAnalysis.register() } - -private func registerUtilities() { - registerVerifier() - registerPhiUpdater() -} diff --git a/SwiftCompilerSources/Sources/Optimizer/PassManager/Passes.swift b/SwiftCompilerSources/Sources/Optimizer/PassManager/Passes.swift index 0e9841bdf55cf..87541053e962b 100644 --- a/SwiftCompilerSources/Sources/Optimizer/PassManager/Passes.swift +++ b/SwiftCompilerSources/Sources/Optimizer/PassManager/Passes.swift @@ -39,7 +39,7 @@ struct ModulePass { self.runFunction = runFunction } - func run(_ bridgedCtxt: BridgedPassContext) { + func run(_ bridgedCtxt: BridgedContext) { let context = ModulePassContext(_bridged: bridgedCtxt) runFunction(context) } diff --git a/SwiftCompilerSources/Sources/Optimizer/PassManager/SimplifyContext.swift b/SwiftCompilerSources/Sources/Optimizer/PassManager/SimplifyContext.swift new file mode 100644 index 0000000000000..2c9b133f4d7e7 --- /dev/null +++ b/SwiftCompilerSources/Sources/Optimizer/PassManager/SimplifyContext.swift @@ -0,0 +1,43 @@ +//===--- SimplifyContext.swift --------------------------------------------===// +// +// This source file is part of the Swift.org open source project +// +// Copyright (c) 2014 - 2025 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 + +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 + } +} diff --git a/SwiftCompilerSources/Sources/Optimizer/TestPasses/CMakeLists.txt b/SwiftCompilerSources/Sources/Optimizer/TestPasses/CMakeLists.txt index 6596426f53102..45bfb439833ad 100644 --- a/SwiftCompilerSources/Sources/Optimizer/TestPasses/CMakeLists.txt +++ b/SwiftCompilerSources/Sources/Optimizer/TestPasses/CMakeLists.txt @@ -16,5 +16,6 @@ swift_compiler_sources(Optimizer SILPrinter.swift RangeDumper.swift RunUnitTests.swift + UpdateBorrowedFrom.swift TestInstructionIteration.swift ) diff --git a/SwiftCompilerSources/Sources/Optimizer/TestPasses/UpdateBorrowedFrom.swift b/SwiftCompilerSources/Sources/Optimizer/TestPasses/UpdateBorrowedFrom.swift new file mode 100644 index 0000000000000..e6fd49f408fca --- /dev/null +++ b/SwiftCompilerSources/Sources/Optimizer/TestPasses/UpdateBorrowedFrom.swift @@ -0,0 +1,22 @@ +//===--- PhiUpdater.swift -------------------------------------------------===// +// +// This source file is part of the Swift.org open source project +// +// Copyright (c) 2014 - 2025 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 + +/// This pass is only used for testing. +/// In the regular pipeline it's not needed because optimization passes must make sure that borrowed-from +/// instructions are updated once the pass finishes. +let updateBorrowedFromPass = FunctionPass(name: "update-borrowed-from") { + (function: Function, context: FunctionPassContext) in + + updateBorrowedFrom(in: function, context) +} diff --git a/SwiftCompilerSources/Sources/Optimizer/Utilities/AccessUtilsTest.swift b/SwiftCompilerSources/Sources/Optimizer/Utilities/AccessUtilsTest.swift deleted file mode 100644 index 99014c26243ee..0000000000000 --- a/SwiftCompilerSources/Sources/Optimizer/Utilities/AccessUtilsTest.swift +++ /dev/null @@ -1,23 +0,0 @@ -//===--- AccessUtils.swift - Utilities for analyzing memory accesses ------===// -// -// 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 -// -//===----------------------------------------------------------------------===// -// -// TODO: Move this to AccessUtils.swift when FunctionTest is available. -// -//===----------------------------------------------------------------------===// - -let getAccessBaseTest = FunctionTest("swift_get_access_base") { - function, arguments, context in - let address = arguments.takeValue() - print("Address: \(address)") - let base = address.accessBase - print("Base: \(base)") -} diff --git a/SwiftCompilerSources/Sources/Optimizer/Utilities/CMakeLists.txt b/SwiftCompilerSources/Sources/Optimizer/Utilities/CMakeLists.txt index ab05966d6195f..50dab7dcccb85 100644 --- a/SwiftCompilerSources/Sources/Optimizer/Utilities/CMakeLists.txt +++ b/SwiftCompilerSources/Sources/Optimizer/Utilities/CMakeLists.txt @@ -7,22 +7,16 @@ # See http://swift.org/CONTRIBUTORS.txt for Swift project authors swift_compiler_sources(Optimizer - AccessUtilsTest.swift AddressUtils.swift - BorrowUtils.swift SpecializationCloner.swift Devirtualization.swift EscapeUtils.swift - ForwardingUtils.swift FunctionSignatureTransforms.swift + FunctionTest.swift GenericSpecialization.swift LifetimeDependenceUtils.swift LocalVariableUtils.swift OptUtils.swift OwnershipLiveness.swift - PhiUpdater.swift - SSAUpdater.swift StaticInitCloner.swift - Test.swift - Verifier.swift ) diff --git a/SwiftCompilerSources/Sources/Optimizer/Utilities/FunctionTest.swift b/SwiftCompilerSources/Sources/Optimizer/Utilities/FunctionTest.swift new file mode 100644 index 0000000000000..984d9609e4eda --- /dev/null +++ b/SwiftCompilerSources/Sources/Optimizer/Utilities/FunctionTest.swift @@ -0,0 +1,105 @@ +//===----------- FunctionTest.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 +// +//===----------------------------------------------------------------------===// +// +// Optimizer test infrastructure. +// +// For general documentation on how to write tests see `Test.swift` in the +// SIL module. +// To add an optimizer test, use `FunctionTest` instead of `Test` and register +// it in `registerOptimizerTests`. +// +//===----------------------------------------------------------------------===// + +import SIL +import OptimizerBridging + +/// Like `SIL.Test`, but provides a `FunctionPass` to the invocation closure. +struct FunctionTest { + let name: String + let invocation: FunctionTestInvocation + + public init(_ name: String, invocation: @escaping FunctionTestInvocation) { + self.name = name + self.invocation = invocation + } +} + +/// The type of the closure passed to a FunctionTest. +typealias FunctionTestInvocation = @convention(thin) (Function, TestArguments, FunctionPassContext) -> () + +public func registerOptimizerTests() { + SIL.registerTests() + + // Register each test. + registerFunctionTests( + addressOwnershipLiveRangeTest, + argumentConventionsTest, + getPullbackClosureInfoTest, + interiorLivenessTest, + lifetimeDependenceRootTest, + lifetimeDependenceScopeTest, + lifetimeDependenceUseTest, + linearLivenessTest, + localVariableReachableUsesTest, + localVariableReachingAssignmentsTest, + rangeOverlapsPathTest, + rewrittenCallerBodyTest, + specializedFunctionSignatureAndBodyTest, + variableIntroducerTest + ) + + // Finally register the thunk they all call through. + registerFunctionTestThunk(functionTestThunk) +} + +private func registerFunctionTests(_ tests: FunctionTest...) { + tests.forEach { registerFunctionTest($0) } +} + +private func registerFunctionTest(_ test: FunctionTest) { + test.name._withBridgedStringRef { ref in + registerFunctionTest(ref, castToOpaquePointer(fromInvocation: test.invocation)) + } +} + +/// The function called by the swift::test::FunctionTest which invokes the +/// actual test function. +/// +/// This function is necessary because tests need to be written in terms of +/// native Swift types (Function, TestArguments, FunctionPassContext) +/// rather than their bridged variants, but such a function isn't representable +/// in C++. This thunk unwraps the bridged types and invokes the real function. +private func functionTestThunk( + _ erasedInvocation: UnsafeMutableRawPointer, + _ function: BridgedFunction, + _ arguments: BridgedTestArguments, + _ bridgedContext: BridgedContext) { + let invocation = castToInvocation(fromOpaquePointer: erasedInvocation) + let context = FunctionPassContext(_bridged: bridgedContext) + invocation(function.function, arguments.native, context) +} + +/// Bitcast a thin test closure to void *. +/// +/// Needed so that the closure can be represented in C++ for storage in the test +/// registry. +private func castToOpaquePointer(fromInvocation invocation: FunctionTestInvocation) -> UnsafeMutableRawPointer { + return unsafeBitCast(invocation, to: UnsafeMutableRawPointer.self) +} + +/// Bitcast a void * to a thin test closure. +/// +/// Needed so that the closure stored in the C++ test registry can be invoked +/// via the functionTestThunk. +private func castToInvocation(fromOpaquePointer erasedInvocation: UnsafeMutableRawPointer) -> FunctionTestInvocation { + return unsafeBitCast(erasedInvocation, to: FunctionTestInvocation.self) +} diff --git a/SwiftCompilerSources/Sources/Optimizer/Utilities/OptUtils.swift b/SwiftCompilerSources/Sources/Optimizer/Utilities/OptUtils.swift index a7a63fe9b2cd6..90c94ca4ba179 100644 --- a/SwiftCompilerSources/Sources/Optimizer/Utilities/OptUtils.swift +++ b/SwiftCompilerSources/Sources/Optimizer/Utilities/OptUtils.swift @@ -341,24 +341,6 @@ extension Value { } } -extension SingleValueInstruction { - /// Replaces all uses with `replacement` and then erases the instruction. - func replace(with replacement: Value, _ context: some MutatingContext) { - uses.replaceAll(with: replacement, context) - context.erase(instruction: self) - } -} - -extension MultipleValueInstruction { - /// Replaces all uses with the result of `replacement` and then erases the instruction. - func replace(with replacement: MultipleValueInstruction, _ context: some MutatingContext) { - for (origResult, newResult) in zip(self.results, replacement.results) { - origResult.uses.replaceAll(with: newResult, context) - } - context.erase(instruction: self) - } -} - extension Instruction { var isTriviallyDead: Bool { if results.contains(where: { !$0.uses.isEmpty }) { @@ -984,7 +966,7 @@ extension Type { if !context.options.useAggressiveReg2MemForCodeSize { return true } - return context._bridged.shouldExpand(self.bridged) + return context.bridgedPassContext.shouldExpand(self.bridged) } } diff --git a/SwiftCompilerSources/Sources/Optimizer/Utilities/OwnershipLiveness.swift b/SwiftCompilerSources/Sources/Optimizer/Utilities/OwnershipLiveness.swift index 3f1ad6afde0e5..2c7841dd4895e 100644 --- a/SwiftCompilerSources/Sources/Optimizer/Utilities/OwnershipLiveness.swift +++ b/SwiftCompilerSources/Sources/Optimizer/Utilities/OwnershipLiveness.swift @@ -84,6 +84,26 @@ func computeKnownLiveness(for definingValue: Value, visitInnerUses: Bool = false visitInnerUses: visitInnerUses, context).acquireRange } +/// Compute the live range for the borrow scopes of a guaranteed value. This returns a separate instruction range for +/// each of the value's borrow introducers. +/// +/// TODO: This should return a single multiply-defined instruction range. +func computeBorrowLiveRange(for value: Value, _ context: FunctionPassContext) + -> SingleInlineArray<(BeginBorrowValue, InstructionRange)> { + assert(value.ownership == .guaranteed) + + var ranges = SingleInlineArray<(BeginBorrowValue, InstructionRange)>() + // If introducers is empty, then the dependence is on a trivial value, so + // there is no ownership range. + for beginBorrow in value.getBorrowIntroducers(context) { + /// FIXME: Remove calls to computeKnownLiveness() as soon as lifetime completion runs immediately after + /// SILGen. Instead, this should compute linear liveness for borrowed value by switching over BeginBorrowValue, just + /// like LifetimeDependence.Scope.computeRange(). + ranges.push((beginBorrow, computeKnownLiveness(for: beginBorrow.value, context))) + } + return ranges +} + /// If any interior pointer may escape, then record the first instance here. If 'ignoreEscape' is true, this /// immediately aborts the walk, so further instances are unavailable. /// @@ -904,3 +924,29 @@ let interiorLivenessTest = FunctionTest("interior_liveness_swift") { defer { boundary.deinitialize() } print(boundary) } + +// +// TODO: Move this to InstructionRange.swift when computeLinearLiveness is in the SIL module. +// +let rangeOverlapsPathTest = FunctionTest("range_overlaps_path") { + function, arguments, context in + let rangeValue = arguments.takeValue() + print("Range of: \(rangeValue)") + var range = computeLinearLiveness(for: rangeValue, context) + defer { range.deinitialize() } + let pathInst = arguments.takeInstruction() + print("Path begin: \(pathInst)") + if let pathBegin = pathInst as? ScopedInstruction { + for end in pathBegin.endInstructions { + print("Overlap kind:", range.overlaps(pathBegin: pathInst, pathEnd: end, context)) + } + return + } + if let pathValue = pathInst as? SingleValueInstruction, pathValue.ownership == .owned { + for end in pathValue.uses.endingLifetime { + print("Overlap kind:", range.overlaps(pathBegin: pathInst, pathEnd: end.instruction, context)) + } + return + } + print("Test specification error: not a scoped or owned instruction: \(pathInst)") +} diff --git a/SwiftCompilerSources/Sources/SIL/Argument.swift b/SwiftCompilerSources/Sources/SIL/Argument.swift index bd7c229bbde98..1cf9886a763af 100644 --- a/SwiftCompilerSources/Sources/SIL/Argument.swift +++ b/SwiftCompilerSources/Sources/SIL/Argument.swift @@ -32,6 +32,11 @@ public class Argument : Value, Hashable { public var isReborrow: Bool { bridged.isReborrow() } + public func set(reborrow: Bool, _ context: some MutatingContext) { + context.notifyInstructionsChanged() + bridged.setReborrow(reborrow) + } + public var isLexical: Bool { false } public var decl: ValueDecl? { bridged.getDecl().getAs(ValueDecl.self) } @@ -83,6 +88,16 @@ final public class FunctionArgument : Argument { public var resultDependence: LifetimeDependenceConvention? { parentFunction.argumentConventions[resultDependsOn: index] } + + /// Copies the following flags from `arg`: + /// 1. noImplicitCopy + /// 2. lifetimeAnnotation + /// 3. closureCapture + /// 4. parameterPack + public func copyFlags(from arg: FunctionArgument, _ context: some MutatingContext) { + context.notifyInstructionsChanged() + bridged.copyFlags(arg.bridged) + } } public struct Phi { diff --git a/SwiftCompilerSources/Sources/SIL/BasicBlock.swift b/SwiftCompilerSources/Sources/SIL/BasicBlock.swift index 3d9613c085adc..dcf5bb68474ec 100644 --- a/SwiftCompilerSources/Sources/SIL/BasicBlock.swift +++ b/SwiftCompilerSources/Sources/SIL/BasicBlock.swift @@ -10,7 +10,7 @@ // //===----------------------------------------------------------------------===// -import Basic +import AST import SILBridging @_semantics("arc.immortal") @@ -25,8 +25,69 @@ final public class BasicBlock : CustomStringConvertible, HasShortDescription, Ha } public var shortDescription: String { name } + /// The index of the basic block in its function. + /// This has O(n) complexity. Only use it for debugging + public var index: Int { + for (idx, block) in parentFunction.blocks.enumerated() { + if block == self { return idx } + } + fatalError() + } + + public var name: String { "bb\(index)" } + + public static func == (lhs: BasicBlock, rhs: BasicBlock) -> Bool { lhs === rhs } + + public func hash(into hasher: inout Hasher) { + hasher.combine(ObjectIdentifier(self)) + } + + public var bridged: BridgedBasicBlock { BridgedBasicBlock(SwiftObject(self)) } + + //===----------------------------------------------------------------------===// + // Arguments + //===----------------------------------------------------------------------===// + public var arguments: ArgumentArray { ArgumentArray(block: self) } + public func addArgument(type: Type, ownership: Ownership, _ context: some MutatingContext) -> Argument { + context.notifyInstructionsChanged() + return bridged.addBlockArgument(type.bridged, ownership._bridged).argument + } + + public func addFunctionArgument(type: Type, _ context: some MutatingContext) -> FunctionArgument { + context.notifyInstructionsChanged() + return bridged.addFunctionArgument(type.bridged).argument as! FunctionArgument + } + + public func insertFunctionArgument(atPosition: Int, type: Type, ownership: Ownership, decl: ValueDecl? = nil, + _ context: some MutatingContext) -> FunctionArgument + { + context.notifyInstructionsChanged() + return bridged.insertFunctionArgument(atPosition, type.bridged, ownership._bridged, + (decl as Decl?).bridged).argument as! FunctionArgument + } + + public func eraseArgument(at index: Int, _ context: some MutatingContext) { + context.notifyInstructionsChanged() + bridged.eraseArgument(index) + } + + public func eraseAllArguments(_ context: some MutatingContext) { + // Arguments are stored in an array. We need to erase in reverse order to avoid quadratic complexity. + for argIdx in (0 ..< arguments.count).reversed() { + eraseArgument(at: argIdx, context) + } + } + + public func moveAllArguments(to otherBlock: BasicBlock, _ context: some MutatingContext) { + bridged.moveArgumentsTo(otherBlock.bridged) + } + + //===----------------------------------------------------------------------===// + // Instructions + //===----------------------------------------------------------------------===// + public var instructions: InstructionList { InstructionList(first: bridged.getFirstInst().instruction) } @@ -35,6 +96,22 @@ final public class BasicBlock : CustomStringConvertible, HasShortDescription, Ha bridged.getLastInst().instruction as! TermInst } + public func moveAllInstructions(toBeginOf otherBlock: BasicBlock, _ context: some MutatingContext) { + context.notifyInstructionsChanged() + context.notifyBranchesChanged() + bridged.moveAllInstructionsToBegin(otherBlock.bridged) + } + + public func moveAllInstructions(toEndOf otherBlock: BasicBlock, _ context: some MutatingContext) { + context.notifyInstructionsChanged() + context.notifyBranchesChanged() + bridged.moveAllInstructionsToEnd(otherBlock.bridged) + } + + //===----------------------------------------------------------------------===// + // predecessors and successors + //===----------------------------------------------------------------------===// + public var successors: SuccessorArray { terminator.successors } public var predecessors: PredecessorList { @@ -76,25 +153,6 @@ final public class BasicBlock : CustomStringConvertible, HasShortDescription, Ha return false } } - - /// The index of the basic block in its function. - /// This has O(n) complexity. Only use it for debugging - public var index: Int { - for (idx, block) in parentFunction.blocks.enumerated() { - if block == self { return idx } - } - fatalError() - } - - public var name: String { "bb\(index)" } - - public static func == (lhs: BasicBlock, rhs: BasicBlock) -> Bool { lhs === rhs } - - public func hash(into hasher: inout Hasher) { - hasher.combine(ObjectIdentifier(self)) - } - - public var bridged: BridgedBasicBlock { BridgedBasicBlock(SwiftObject(self)) } } /// The list of instructions in a BasicBlock. diff --git a/SwiftCompilerSources/Sources/SIL/Builder.swift b/SwiftCompilerSources/Sources/SIL/Builder.swift index 79989878c32a6..59f4cd86263ea 100644 --- a/SwiftCompilerSources/Sources/SIL/Builder.swift +++ b/SwiftCompilerSources/Sources/SIL/Builder.swift @@ -26,9 +26,90 @@ public struct Builder { public let insertionPoint: InsertionPoint let location: Location - private let notificationHandler: BridgedChangeNotificationHandler + private let notificationHandler: BridgedContext private let notifyNewInstruction: (Instruction) -> () + /// Creates a builder which inserts _before_ `insPnt`, using a custom `location`. + public init(before insPnt: Instruction, location: Location, _ context: some MutatingContext) { + context.verifyIsTransforming(function: insPnt.parentFunction) + self.init(insertAt: .before(insPnt), location: location, context.notifyInstructionChanged, context._bridged) + } + + /// Creates a builder which inserts before `insPnt`, using `insPnt`'s next + /// non-meta instruction's location. + /// This function should be used when moving code to an unknown insert point, + /// when we want to inherit the location of the closest non-meta instruction. + /// For replacing an existing meta instruction with another, use + /// ``Builder.init(replacing:_:)``. + public init(before insPnt: Instruction, _ context: some MutatingContext) { + context.verifyIsTransforming(function: insPnt.parentFunction) + self.init(insertAt: .before(insPnt), location: insPnt.location, + context.notifyInstructionChanged, context._bridged) + } + + /// Creates a builder which inserts _before_ `insPnt`, using the exact location of `insPnt`, + /// for the purpose of replacing that meta instruction with an equivalent instruction. + /// This function does not delete `insPnt`. + public init(replacing insPnt: MetaInstruction, _ context: some MutatingContext) { + context.verifyIsTransforming(function: insPnt.parentFunction) + self.init(insertAt: .before(insPnt), location: insPnt.location, context.notifyInstructionChanged, context._bridged) + } + + /// Creates a builder which inserts _after_ `insPnt`, using a custom `location`. + /// + /// TODO: this is usually incorrect for terminator instructions. Instead use + /// `Builder.insert(after:location:_:insertFunc)` from OptUtils.swift. Rename this to afterNonTerminator. + public init(after insPnt: Instruction, location: Location, _ context: some MutatingContext) { + context.verifyIsTransforming(function: insPnt.parentFunction) + guard let nextInst = insPnt.next else { + fatalError("cannot insert an instruction after a block terminator.") + } + self.init(insertAt: .before(nextInst), location: location, context.notifyInstructionChanged, context._bridged) + } + + /// Creates a builder which inserts _after_ `insPnt`, using `insPnt`'s next + /// non-meta instruction's location. + /// + /// TODO: this is incorrect for terminator instructions. Instead use `Builder.insert(after:location:_:insertFunc)` + /// from OptUtils.swift. Rename this to afterNonTerminator. + public init(after insPnt: Instruction, _ context: some MutatingContext) { + self.init(after: insPnt, location: insPnt.location, context) + } + + /// Creates a builder which inserts at the end of `block`, using a custom `location`. + public init(atEndOf block: BasicBlock, location: Location, _ context: some MutatingContext) { + context.verifyIsTransforming(function: block.parentFunction) + self.init(insertAt: .atEndOf(block), location: location, context.notifyInstructionChanged, context._bridged) + } + + /// Creates a builder which inserts at the begin of `block`, using a custom `location`. + public init(atBeginOf block: BasicBlock, location: Location, _ context: some MutatingContext) { + context.verifyIsTransforming(function: block.parentFunction) + let firstInst = block.instructions.first! + self.init(insertAt: .before(firstInst), location: location, context.notifyInstructionChanged, context._bridged) + } + + /// Creates a builder which inserts at the begin of `block`, using the location of the first + /// non-meta instruction of `block`. + public init(atBeginOf block: BasicBlock, _ context: some MutatingContext) { + context.verifyIsTransforming(function: block.parentFunction) + let firstInst = block.instructions.first! + self.init(insertAt: .before(firstInst), + location: firstInst.location, context.notifyInstructionChanged, context._bridged) + } + + /// Creates a builder which inserts instructions into an empty function, using the location of the function itself. + public init(atStartOf function: Function, _ context: some MutatingContext) { + context.verifyIsTransforming(function: function) + self.init(insertAt: .atStartOf(function), location: function.location, + context.notifyInstructionChanged, context._bridged) + } + + public init(staticInitializerOf global: GlobalVariable, _ context: some MutatingContext) { + self.init(insertAt: .staticInitializer(global), + location: Location.artificialUnreachableLocation, { _ in }, context._bridged) + } + /// Return 'nil' when inserting at the start of a function or in a global initializer. public var insertionBlock: BasicBlock? { switch insertionPoint { @@ -59,20 +140,20 @@ public struct Builder { } private func notifyNew(_ instruction: I) -> I { - notificationHandler.notifyChanges(.instructionsChanged) + notificationHandler.notifyChanges(.Instructions) if instruction is FullApplySite { - notificationHandler.notifyChanges(.callsChanged) + notificationHandler.notifyChanges(.Calls) } if instruction is TermInst { - notificationHandler.notifyChanges(.branchesChanged) + notificationHandler.notifyChanges(.Branches) } notifyNewInstruction(instruction) return instruction } - public init(insertAt: InsertionPoint, location: Location, + private init(insertAt: InsertionPoint, location: Location, _ notifyNewInstruction: @escaping (Instruction) -> (), - _ notificationHandler: BridgedChangeNotificationHandler) { + _ notificationHandler: BridgedContext) { self.insertionPoint = insertAt self.location = location; self.notifyNewInstruction = notifyNewInstruction diff --git a/SwiftCompilerSources/Sources/SIL/CMakeLists.txt b/SwiftCompilerSources/Sources/SIL/CMakeLists.txt index 12cf7737028c6..8d4c2ac9275ac 100644 --- a/SwiftCompilerSources/Sources/SIL/CMakeLists.txt +++ b/SwiftCompilerSources/Sources/SIL/CMakeLists.txt @@ -17,6 +17,7 @@ add_swift_compiler_module(SIL BasicBlock.swift Builder.swift ConstExpressionEvaluator.swift + Context.swift DeclRef.swift Effects.swift ForwardingInstruction.swift @@ -34,5 +35,6 @@ add_swift_compiler_module(SIL VTable.swift WitnessTable.swift) +add_subdirectory(DataStructures) add_subdirectory(Utilities) diff --git a/SwiftCompilerSources/Sources/SIL/Context.swift b/SwiftCompilerSources/Sources/SIL/Context.swift new file mode 100644 index 0000000000000..7109968338429 --- /dev/null +++ b/SwiftCompilerSources/Sources/SIL/Context.swift @@ -0,0 +1,196 @@ +//===--- Context.swift - defines the context protocols --------------------===// +// +// This source file is part of the Swift.org open source project +// +// Copyright (c) 2014 - 2025 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 SILBridging +import AST + +public protocol Context { + var _bridged: BridgedContext { get } +} + +/// A context which allows mutation of a function's SIL. +public protocol MutatingContext : Context { + // Called by all instruction mutations, including inserted new instructions. + var notifyInstructionChanged: (Instruction) -> () { get } +} + +/// Common funcationality of all Contexts. +extension Context { + public var silStage: SILStage { + switch _bridged.getSILStage() { + case .Raw: return .raw + case .Canonical: return .canonical + case .Lowered: return .lowered + default: fatalError("unhandled SILStage case") + } + } + + public var currentModuleContext: ModuleDecl { + _bridged.getCurrentModuleContext().getAs(ModuleDecl.self) + } + + public var moduleIsSerialized: Bool { _bridged.moduleIsSerialized() } + + public var moduleHasLoweredAddresses: Bool { _bridged.moduleHasLoweredAddresses() } + + public func lookupDeinit(ofNominal: NominalTypeDecl) -> Function? { + _bridged.lookUpNominalDeinitFunction(ofNominal.bridged).function + } + + public func getBuiltinIntegerType(bitWidth: Int) -> Type { _bridged.getBuiltinIntegerType(bitWidth).type } + + public var swiftArrayDecl: NominalTypeDecl { + _bridged.getSwiftArrayDecl().getAs(NominalTypeDecl.self) + } + + public var swiftMutableSpan: NominalTypeDecl { + _bridged.getSwiftMutableSpanDecl().getAs(NominalTypeDecl.self) + } + + public func lookupFunction(name: String) -> Function? { + name._withBridgedStringRef { + _bridged.lookupFunction($0).function + } + } + + public func lookupWitnessTable(for conformance: Conformance) -> WitnessTable? { + return _bridged.lookupWitnessTable(conformance.bridged).witnessTable + } + + public func lookupVTable(for classDecl: NominalTypeDecl) -> VTable? { + return _bridged.lookupVTable(classDecl.bridged).vTable + } + + public func lookupSpecializedVTable(for classType: Type) -> VTable? { + return _bridged.lookupSpecializedVTable(classType.bridged).vTable + } + + /// Looks up a function in the `Swift` module. + /// The `name` is the source name of the function and not the mangled name. + /// Returns nil if no such function or multiple matching functions are found. + public func lookupStdlibFunction(name: StaticString) -> Function? { + return name.withUTF8Buffer { (nameBuffer: UnsafeBufferPointer) in + let nameStr = BridgedStringRef(data: nameBuffer.baseAddress, count: nameBuffer.count) + return _bridged.lookupStdlibFunction(nameStr).function + } + } + + public func getSpecializedConformance(of genericConformance: Conformance, + for type: AST.`Type`, + substitutions: SubstitutionMap) -> Conformance + { + let c = _bridged.getSpecializedConformance(genericConformance.bridged, type.bridged, substitutions.bridged) + return Conformance(bridged: c) + } +} + +extension MutatingContext { + public func verifyIsTransforming(function: Function) { + precondition(_bridged.isTransforming(function.bridged), "pass modifies wrong function") + } + + public func notifyInstructionsChanged() { + _bridged.notifyChanges(.Instructions) + } + + public func notifyCallsChanged() { + _bridged.notifyChanges(.Calls) + } + + public func notifyBranchesChanged() { + _bridged.notifyChanges(.Branches) + } + + public func notifyEffectsChanged() { + _bridged.notifyChanges(.Effects) + } + + public func createGlobalVariable(name: String, type: Type, linkage: Linkage, isLet: Bool) -> GlobalVariable { + let gv = name._withBridgedStringRef { + _bridged.createGlobalVariable($0, type.bridged, linkage.bridged, isLet) + } + return gv.globalVar + } + + /// Splits the basic block, which contains `inst`, before `inst` and returns the + /// new block. + /// + /// `inst` and all subsequent instructions are moved to the new block, while all + /// instructions _before_ `inst` remain in the original block. + public func splitBlock(before inst: Instruction) -> BasicBlock { + notifyBranchesChanged() + return _bridged.splitBlockBefore(inst.bridged).block + } + + /// Splits the basic block, which contains `inst`, after `inst` and returns the + /// new block. + /// + /// All subsequent instructions after `inst` are moved to the new block, while `inst` and all + /// instructions _before_ `inst` remain in the original block. + public func splitBlock(after inst: Instruction) -> BasicBlock { + notifyBranchesChanged() + return _bridged.splitBlockAfter(inst.bridged).block + } + + public func createBlock(after block: BasicBlock) -> BasicBlock { + notifyBranchesChanged() + return _bridged.createBlockAfter(block.bridged).block + } + + /// Removes and deletes `instruction`. + /// If `salvageDebugInfo` is true, compensating `debug_value` instructions are inserted for certain + /// kind of instructions. + public func erase(instruction: Instruction, salvageDebugInfo: Bool = true) { + if !instruction.isInStaticInitializer { + verifyIsTransforming(function: instruction.parentFunction) + } + if instruction is FullApplySite { + notifyCallsChanged() + } + if instruction is TermInst { + notifyBranchesChanged() + } + notifyInstructionsChanged() + + _bridged.eraseInstruction(instruction.bridged, salvageDebugInfo) + } + + public func erase(instructionIncludingAllUsers inst: Instruction) { + if inst.isDeleted { + return + } + for result in inst.results { + for use in result.uses { + erase(instructionIncludingAllUsers: use.instruction) + } + } + // We rely that after deleting the instruction its operands have no users. + // Therefore `salvageDebugInfo` must be turned off because we cannot insert debug_value instructions. + erase(instruction: inst, salvageDebugInfo: false) + } + + public func erase(instructions: S) where S.Element: Instruction { + for inst in instructions { + erase(instruction: inst) + } + } + + public func erase(instructionIncludingDebugUses inst: Instruction) { + precondition(inst.results.allSatisfy { $0.uses.ignoreDebugUses.isEmpty }) + erase(instructionIncludingAllUsers: inst) + } + + public func erase(block: BasicBlock) { + _bridged.eraseBlock(block.bridged) + } + +} diff --git a/SwiftCompilerSources/Sources/Optimizer/DataStructures/BasicBlockRange.swift b/SwiftCompilerSources/Sources/SIL/DataStructures/BasicBlockRange.swift similarity index 85% rename from SwiftCompilerSources/Sources/Optimizer/DataStructures/BasicBlockRange.swift rename to SwiftCompilerSources/Sources/SIL/DataStructures/BasicBlockRange.swift index 29f9b9a5d1618..140a746a41d6a 100644 --- a/SwiftCompilerSources/Sources/Optimizer/DataStructures/BasicBlockRange.swift +++ b/SwiftCompilerSources/Sources/SIL/DataStructures/BasicBlockRange.swift @@ -10,8 +10,6 @@ // //===----------------------------------------------------------------------===// -import SIL - /// A range of basic blocks. /// /// The `BasicBlockRange` defines a range from a dominating "begin" block to one or more "end" blocks. @@ -46,16 +44,16 @@ import SIL /// This type should be a move-only type, but unfortunately we don't have move-only /// types yet. Therefore it's needed to call `deinitialize()` explicitly to /// destruct this data structure, e.g. in a `defer {}` block. -struct BasicBlockRange : CustomStringConvertible, NoReflectionChildren { +public struct BasicBlockRange : CustomStringConvertible, NoReflectionChildren { /// The dominating begin block. - let begin: BasicBlock + public let begin: BasicBlock /// The inclusive range, i.e. the exclusive range plus the end blocks. - private(set) var inclusiveRange: Stack - + public private(set) var inclusiveRange: Stack + /// The exclusive range, i.e. not containing the end blocks. - var range: LazyFilterSequence> { + public var range: LazyFilterSequence> { inclusiveRange.lazy.filter { contains($0) } } @@ -66,7 +64,7 @@ struct BasicBlockRange : CustomStringConvertible, NoReflectionChildren { private var inExclusiveRange: BasicBlockSet private var worklist: BasicBlockWorklist - init(begin: BasicBlock, _ context: some Context) { + public init(begin: BasicBlock, _ context: some Context) { self.begin = begin self.inclusiveRange = Stack(context) self.inserted = Stack(context) @@ -81,7 +79,7 @@ struct BasicBlockRange : CustomStringConvertible, NoReflectionChildren { /// Returns true if the begin-block is reached during backward propagation. /// Usually this is not relevant, but InstructionRange needs this information. @discardableResult - mutating func insert(_ block: BasicBlock) -> Bool { + public mutating func insert(_ block: BasicBlock) -> Bool { if wasInserted.insert(block) { inserted.append(block) } @@ -103,22 +101,22 @@ struct BasicBlockRange : CustomStringConvertible, NoReflectionChildren { } /// Insert a sequence of potential end blocks. - mutating func insert(contentsOf other: S) where S.Element == BasicBlock { + public mutating func insert(contentsOf other: S) where S.Element == BasicBlock { for block in other { insert(block) } } /// Returns true if the exclusive range contains `block`. - func contains(_ block: BasicBlock) -> Bool { inExclusiveRange.contains(block) } - + public func contains(_ block: BasicBlock) -> Bool { inExclusiveRange.contains(block) } + /// Returns true if the inclusive range contains `block`. - func inclusiveRangeContains (_ block: BasicBlock) -> Bool { + public func inclusiveRangeContains (_ block: BasicBlock) -> Bool { worklist.hasBeenPushed(block) } /// Returns true if the range is valid and that's iff the begin block dominates all blocks of the range. - var isValid: Bool { + public var isValid: Bool { let entry = begin.parentFunction.entryBlock return begin == entry || // If any block in the range is not dominated by `begin`, the range propagates back to the entry block. @@ -126,12 +124,12 @@ struct BasicBlockRange : CustomStringConvertible, NoReflectionChildren { } /// Returns the end blocks. - var ends: LazyFilterSequence> { + public var ends: LazyFilterSequence> { inserted.lazy.filter { !contains($0) } } /// Returns the exit blocks. - var exits: LazySequence>, LazyFilterSequence>>> { range.flatMap { @@ -142,11 +140,11 @@ struct BasicBlockRange : CustomStringConvertible, NoReflectionChildren { } /// Returns the interior blocks. - var interiors: LazyFilterSequence> { + public var interiors: LazyFilterSequence> { inserted.lazy.filter { contains($0) && $0 != begin } } - var description: String { + public var description: String { return (isValid ? "" : "\n") + """ begin: \(begin.name) @@ -159,7 +157,7 @@ struct BasicBlockRange : CustomStringConvertible, NoReflectionChildren { } /// TODO: once we have move-only types, make this a real deinit. - mutating func deinitialize() { + public mutating func deinitialize() { worklist.deinitialize() inExclusiveRange.deinitialize() wasInserted.deinitialize() diff --git a/SwiftCompilerSources/Sources/SIL/DataStructures/CMakeLists.txt b/SwiftCompilerSources/Sources/SIL/DataStructures/CMakeLists.txt new file mode 100644 index 0000000000000..7564b469aa421 --- /dev/null +++ b/SwiftCompilerSources/Sources/SIL/DataStructures/CMakeLists.txt @@ -0,0 +1,14 @@ +# 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 http://swift.org/LICENSE.txt for license information +# See http://swift.org/CONTRIBUTORS.txt for Swift project authors + +swift_compiler_sources(SIL + BasicBlockRange.swift + InstructionRange.swift + Set.swift + Stack.swift + Worklist.swift) diff --git a/SwiftCompilerSources/Sources/Optimizer/DataStructures/InstructionRange.swift b/SwiftCompilerSources/Sources/SIL/DataStructures/InstructionRange.swift similarity index 81% rename from SwiftCompilerSources/Sources/Optimizer/DataStructures/InstructionRange.swift rename to SwiftCompilerSources/Sources/SIL/DataStructures/InstructionRange.swift index ab823c384ecc1..c2acd2ca7a35b 100644 --- a/SwiftCompilerSources/Sources/Optimizer/DataStructures/InstructionRange.swift +++ b/SwiftCompilerSources/Sources/SIL/DataStructures/InstructionRange.swift @@ -10,8 +10,6 @@ // //===----------------------------------------------------------------------===// -import SIL - /// A range of instructions. /// /// The `InstructionRange` defines a range from a dominating "begin" instruction to one or more "end" instructions. @@ -38,29 +36,29 @@ import SIL /// This type should be a move-only type, but unfortunately we don't have move-only /// types yet. Therefore it's needed to call `deinitialize()` explicitly to /// destruct this data structure, e.g. in a `defer {}` block. -struct InstructionRange : CustomStringConvertible, NoReflectionChildren { - +public struct InstructionRange : CustomStringConvertible, NoReflectionChildren { + /// The underlying block range. - private(set) var blockRange: BasicBlockRange + public private(set) var blockRange: BasicBlockRange private var insertedInsts: InstructionSet // For efficiency, this set does not include instructions in blocks which are not the begin or any end block. private var inExclusiveRange: InstructionSet - init(begin beginInst: Instruction, _ context: some Context) { + public init(begin beginInst: Instruction, _ context: some Context) { self = InstructionRange(beginBlock: beginInst.parentBlock, context) self.inExclusiveRange.insert(beginInst) } // Note: 'ends' are simply the instructions to insert in the range. 'self.ends' might not return the same sequence // as this 'ends' argument because 'self.ends' will not include block exits. - init(begin beginInst: Instruction, ends: S, _ context: some Context) where S.Element: Instruction { + public init(begin beginInst: Instruction, ends: S, _ context: some Context) where S.Element: Instruction { self = InstructionRange(begin: beginInst, context) insert(contentsOf: ends) } - init(for value: Value, _ context: some Context) { + public init(for value: Value, _ context: some Context) { if let inst = value.definingInstruction { self = InstructionRange(begin: inst, context) } else if let arg = value as? Argument { @@ -77,7 +75,7 @@ struct InstructionRange : CustomStringConvertible, NoReflectionChildren { } /// Insert a potential end instruction. - mutating func insert(_ inst: Instruction) { + public mutating func insert(_ inst: Instruction) { insertedInsts.insert(inst) insertIntoRange(instructions: ReverseInstructionList(first: inst.previous)) if blockRange.insert(inst.parentBlock) { @@ -90,14 +88,14 @@ struct InstructionRange : CustomStringConvertible, NoReflectionChildren { } /// Insert a sequence of potential end instructions. - mutating func insert(contentsOf other: S) where S.Element: Instruction { + public mutating func insert(contentsOf other: S) where S.Element: Instruction { for inst in other { insert(inst) } } /// Returns true if the exclusive range contains `inst`. - func contains(_ inst: Instruction) -> Bool { + public func contains(_ inst: Instruction) -> Bool { if inExclusiveRange.contains(inst) { return true } @@ -106,37 +104,37 @@ struct InstructionRange : CustomStringConvertible, NoReflectionChildren { } /// Returns true if the inclusive range contains `inst`. - func inclusiveRangeContains (_ inst: Instruction) -> Bool { + public func inclusiveRangeContains (_ inst: Instruction) -> Bool { contains(inst) || insertedInsts.contains(inst) } /// Returns the end instructions. /// /// Warning: this returns `begin` if no instructions were inserted. - var ends: LazyMapSequence>, Instruction> { + public var ends: LazyMapSequence>, Instruction> { blockRange.ends.map { $0.instructions.reversed().first(where: { insertedInsts.contains($0)})! } } // Returns the exit blocks. - var exitBlocks: LazySequence>, + public var exitBlocks: LazySequence>, LazyFilterSequence>>> { blockRange.exits } /// Returns the exit instructions. - var exits: LazyMapSequence>, + public var exits: LazyMapSequence>, LazyFilterSequence>>>, Instruction> { blockRange.exits.lazy.map { $0.instructions.first! } } /// Returns the interior instructions. - var interiors: LazySequence, + public var interiors: LazySequence, LazyFilterSequence>>> { blockRange.inserted.lazy.flatMap { var include = blockRange.contains($0) @@ -151,7 +149,7 @@ struct InstructionRange : CustomStringConvertible, NoReflectionChildren { } } - var begin: Instruction? { + public var begin: Instruction? { blockRange.begin.instructions.first(where: inExclusiveRange.contains) } @@ -163,7 +161,7 @@ struct InstructionRange : CustomStringConvertible, NoReflectionChildren { } } - var description: String { + public var description: String { return (blockRange.isValid ? "" : "\n") + """ begin: \(begin?.description ?? blockRange.begin.name) @@ -174,7 +172,7 @@ struct InstructionRange : CustomStringConvertible, NoReflectionChildren { } /// TODO: once we have move-only types, make this a real deinit. - mutating func deinitialize() { + public mutating func deinitialize() { inExclusiveRange.deinitialize() insertedInsts.deinitialize() blockRange.deinitialize() @@ -182,7 +180,7 @@ struct InstructionRange : CustomStringConvertible, NoReflectionChildren { } extension InstructionRange { - enum PathOverlap { + public enum PathOverlap { // range: --- // | pathBegin // | | @@ -226,7 +224,7 @@ extension InstructionRange { /// Returns .containsBegin, if this range has the same begin and end as the path. /// /// Precondition: `begin` dominates `end`. - func overlaps(pathBegin: Instruction, pathEnd: Instruction, _ context: some Context) -> PathOverlap { + public func overlaps(pathBegin: Instruction, pathEnd: Instruction, _ context: some Context) -> PathOverlap { assert(pathBegin != pathEnd, "expect an exclusive path") if contains(pathBegin) { // Note: pathEnd != self.begin here since self.contains(pathBegin) @@ -277,25 +275,3 @@ extension InstructionRange { } } -let rangeOverlapsPathTest = FunctionTest("range_overlaps_path") { - function, arguments, context in - let rangeValue = arguments.takeValue() - print("Range of: \(rangeValue)") - var range = computeLinearLiveness(for: rangeValue, context) - defer { range.deinitialize() } - let pathInst = arguments.takeInstruction() - print("Path begin: \(pathInst)") - if let pathBegin = pathInst as? ScopedInstruction { - for end in pathBegin.endInstructions { - print("Overlap kind:", range.overlaps(pathBegin: pathInst, pathEnd: end, context)) - } - return - } - if let pathValue = pathInst as? SingleValueInstruction, pathValue.ownership == .owned { - for end in pathValue.uses.endingLifetime { - print("Overlap kind:", range.overlaps(pathBegin: pathInst, pathEnd: end.instruction, context)) - } - return - } - print("Test specification error: not a scoped or owned instruction: \(pathInst)") -} diff --git a/SwiftCompilerSources/Sources/Optimizer/DataStructures/Set.swift b/SwiftCompilerSources/Sources/SIL/DataStructures/Set.swift similarity index 70% rename from SwiftCompilerSources/Sources/Optimizer/DataStructures/Set.swift rename to SwiftCompilerSources/Sources/SIL/DataStructures/Set.swift index fe3f6b1d7b5ed..d631a35797811 100644 --- a/SwiftCompilerSources/Sources/Optimizer/DataStructures/Set.swift +++ b/SwiftCompilerSources/Sources/SIL/DataStructures/Set.swift @@ -10,10 +10,9 @@ // //===----------------------------------------------------------------------===// -import SIL -import OptimizerBridging +import SILBridging -protocol IntrusiveSet : CustomStringConvertible, NoReflectionChildren { +public protocol IntrusiveSet : CustomStringConvertible, NoReflectionChildren { associatedtype Element init(_ context: some Context) @@ -31,31 +30,31 @@ protocol IntrusiveSet : CustomStringConvertible, NoReflectionChildren { /// This type should be a move-only type, but unfortunately we don't have move-only /// types yet. Therefore it's needed to call `deinitialize()` explicitly to /// destruct this data structure, e.g. in a `defer {}` block. -struct BasicBlockSet : IntrusiveSet { +public struct BasicBlockSet : IntrusiveSet { - private let context: BridgedPassContext + private let context: BridgedContext private let bridged: BridgedBasicBlockSet - init(_ context: some Context) { + public init(_ context: some Context) { self.context = context._bridged self.bridged = self.context.allocBasicBlockSet() } - func contains(_ block: BasicBlock) -> Bool { + public func contains(_ block: BasicBlock) -> Bool { bridged.contains(block.bridged) } /// Returns true if `block` was not contained in the set before inserting. @discardableResult - mutating func insert(_ block: BasicBlock) -> Bool { + public mutating func insert(_ block: BasicBlock) -> Bool { bridged.insert(block.bridged) } - mutating func erase(_ block: BasicBlock) { + public mutating func erase(_ block: BasicBlock) { bridged.erase(block.bridged) } - var description: String { + public var description: String { let function = bridged.getFunction().function let blockNames = function.blocks.enumerated().filter { contains($0.1) } .map { "bb\($0.0)"} @@ -63,7 +62,7 @@ struct BasicBlockSet : IntrusiveSet { } /// TODO: once we have move-only types, make this a real deinit. - mutating func deinitialize() { + public mutating func deinitialize() { context.freeBasicBlockSet(bridged) } } @@ -76,31 +75,31 @@ struct BasicBlockSet : IntrusiveSet { /// This type should be a move-only type, but unfortunately we don't have move-only /// types yet. Therefore it's needed to call `deinitialize()` explicitly to /// destruct this data structure, e.g. in a `defer {}` block. -struct ValueSet : IntrusiveSet { +public struct ValueSet : IntrusiveSet { - private let context: BridgedPassContext + private let context: BridgedContext private let bridged: BridgedNodeSet - init(_ context: some Context) { + public init(_ context: some Context) { self.context = context._bridged self.bridged = self.context.allocNodeSet() } - func contains(_ value: Value) -> Bool { + public func contains(_ value: Value) -> Bool { bridged.containsValue(value.bridged) } /// Returns true if `value` was not contained in the set before inserting. @discardableResult - mutating func insert(_ value: Value) -> Bool { + public mutating func insert(_ value: Value) -> Bool { bridged.insertValue(value.bridged) } - mutating func erase(_ value: Value) { + public mutating func erase(_ value: Value) { bridged.eraseValue(value.bridged) } - var description: String { + public var description: String { let function = bridged.getFunction().function var d = "{\n" for block in function.blocks { @@ -122,7 +121,7 @@ struct ValueSet : IntrusiveSet { } /// TODO: once we have move-only types, make this a real deinit. - mutating func deinitialize() { + public mutating func deinitialize() { context.freeNodeSet(bridged) } } @@ -135,31 +134,31 @@ struct ValueSet : IntrusiveSet { /// This type should be a move-only type, but unfortunately we don't have move-only /// types yet. Therefore it's needed to call `deinitialize()` explicitly to /// destruct this data structure, e.g. in a `defer {}` block. -struct SpecificInstructionSet : IntrusiveSet { +public struct SpecificInstructionSet : IntrusiveSet { - private let context: BridgedPassContext + private let context: BridgedContext private let bridged: BridgedNodeSet - init(_ context: some Context) { + public init(_ context: some Context) { self.context = context._bridged self.bridged = self.context.allocNodeSet() } - func contains(_ inst: InstType) -> Bool { + public func contains(_ inst: InstType) -> Bool { bridged.containsInstruction(inst.bridged) } /// Returns true if `inst` was not contained in the set before inserting. @discardableResult - mutating func insert(_ inst: InstType) -> Bool { + public mutating func insert(_ inst: InstType) -> Bool { bridged.insertInstruction(inst.bridged) } - mutating func erase(_ inst: InstType) { + public mutating func erase(_ inst: InstType) { bridged.eraseInstruction(inst.bridged) } - var description: String { + public var description: String { let function = bridged.getFunction().function var d = "{\n" for i in function.instructions { @@ -172,27 +171,27 @@ struct SpecificInstructionSet : IntrusiveSet { } /// TODO: once we have move-only types, make this a real deinit. - mutating func deinitialize() { + public mutating func deinitialize() { context.freeNodeSet(bridged) } } /// An `InstructionSet` which also provides a `count` property. -struct SpecificInstructionSetWithCount : IntrusiveSet { - private(set) var count = 0 +public struct SpecificInstructionSetWithCount : IntrusiveSet { + public private(set) var count = 0 private var underlyingSet: SpecificInstructionSet - init(_ context: some Context) { + public init(_ context: some Context) { self.underlyingSet = SpecificInstructionSet(context) } - func contains(_ inst: InstType) -> Bool { underlyingSet.contains(inst) } + public func contains(_ inst: InstType) -> Bool { underlyingSet.contains(inst) } - var isEmpty: Bool { count == 0 } + public var isEmpty: Bool { count == 0 } /// Returns true if `inst` was not contained in the set before inserting. @discardableResult - mutating func insert(_ inst: InstType) -> Bool { + public mutating func insert(_ inst: InstType) -> Bool { if underlyingSet.insert(inst) { count += 1 return true @@ -200,7 +199,7 @@ struct SpecificInstructionSetWithCount : IntrusiveSet { return false } - mutating func erase(_ inst: InstType) { + public mutating func erase(_ inst: InstType) { if underlyingSet.contains(inst) { count -= 1 assert(count >= 0) @@ -208,13 +207,13 @@ struct SpecificInstructionSetWithCount : IntrusiveSet { underlyingSet.erase(inst) } - var description: String { underlyingSet.description } + public var description: String { underlyingSet.description } - mutating func deinitialize() { underlyingSet.deinitialize() } + public mutating func deinitialize() { underlyingSet.deinitialize() } } -typealias InstructionSet = SpecificInstructionSet -typealias InstructionSetWithCount = SpecificInstructionSetWithCount +public typealias InstructionSet = SpecificInstructionSet +public typealias InstructionSetWithCount = SpecificInstructionSetWithCount /// A set of operands. /// @@ -224,31 +223,31 @@ typealias InstructionSetWithCount = SpecificInstructionSetWithCount /// This type should be a move-only type, but unfortunately we don't have move-only /// types yet. Therefore it's needed to call `deinitialize()` explicitly to /// destruct this data structure, e.g. in a `defer {}` block. -struct OperandSet : IntrusiveSet { +public struct OperandSet : IntrusiveSet { - private let context: BridgedPassContext + private let context: BridgedContext private let bridged: BridgedOperandSet - init(_ context: some Context) { + public init(_ context: some Context) { self.context = context._bridged self.bridged = self.context.allocOperandSet() } - func contains(_ operand: Operand) -> Bool { + public func contains(_ operand: Operand) -> Bool { bridged.contains(operand.bridged) } /// Returns true if `inst` was not contained in the set before inserting. @discardableResult - mutating func insert(_ operand: Operand) -> Bool { + public mutating func insert(_ operand: Operand) -> Bool { bridged.insert(operand.bridged) } - mutating func erase(_ operand: Operand) { + public mutating func erase(_ operand: Operand) { bridged.erase(operand.bridged) } - var description: String { + public var description: String { let function = bridged.getFunction().function var d = "{\n" for inst in function.instructions { @@ -263,13 +262,13 @@ struct OperandSet : IntrusiveSet { } /// TODO: once we have move-only types, make this a real deinit. - mutating func deinitialize() { + public mutating func deinitialize() { context.freeOperandSet(bridged) } } extension InstructionSet { - mutating func insert(contentsOf source: some Sequence) { + public mutating func insert(contentsOf source: some Sequence) { for inst in source { _ = insert(inst) } @@ -277,13 +276,13 @@ extension InstructionSet { } extension IntrusiveSet { - mutating func insert(contentsOf source: some Sequence) { + public mutating func insert(contentsOf source: some Sequence) { for element in source { _ = insert(element) } } - init(insertContentsOf source: some Sequence, _ context: some Context) { + public init(insertContentsOf source: some Sequence, _ context: some Context) { self.init(context) insert(contentsOf: source) } diff --git a/SwiftCompilerSources/Sources/Optimizer/DataStructures/Stack.swift b/SwiftCompilerSources/Sources/SIL/DataStructures/Stack.swift similarity index 80% rename from SwiftCompilerSources/Sources/Optimizer/DataStructures/Stack.swift rename to SwiftCompilerSources/Sources/SIL/DataStructures/Stack.swift index c38e8da5404f5..026e42fac92ab 100644 --- a/SwiftCompilerSources/Sources/Optimizer/DataStructures/Stack.swift +++ b/SwiftCompilerSources/Sources/SIL/DataStructures/Stack.swift @@ -10,8 +10,7 @@ // //===----------------------------------------------------------------------===// -import OptimizerBridging -import SIL +import SILBridging /// A very efficient implementation of a stack, which can also be iterated over. /// @@ -24,39 +23,39 @@ import SIL /// This type should be a move-only type, but unfortunately we don't have move-only /// types yet. Therefore it's needed to call `deinitialize()` explicitly to /// destruct this data structure, e.g. in a `defer {}` block. -struct Stack : CollectionLikeSequence { +public struct Stack : CollectionLikeSequence { - private let bridgedContext: BridgedPassContext - private var firstSlab = BridgedPassContext.Slab(nil) - private var lastSlab = BridgedPassContext.Slab(nil) + private let bridgedContext: BridgedContext + private var firstSlab = BridgedContext.Slab(nil) + private var lastSlab = BridgedContext.Slab(nil) private var endIndex: Int = 0 private static var slabCapacity: Int { - BridgedPassContext.Slab.getCapacity() / MemoryLayout.stride + BridgedContext.Slab.getCapacity() / MemoryLayout.stride } - private func allocate(after lastSlab: BridgedPassContext.Slab? = nil) -> BridgedPassContext.Slab { - let lastSlab = lastSlab ?? BridgedPassContext.Slab(nil) + private func allocate(after lastSlab: BridgedContext.Slab? = nil) -> BridgedContext.Slab { + let lastSlab = lastSlab ?? BridgedContext.Slab(nil) let newSlab = bridgedContext.allocSlab(lastSlab) UnsafeMutableRawPointer(newSlab.data!).bindMemory(to: Element.self, capacity: Stack.slabCapacity) return newSlab } - private static func element(in slab: BridgedPassContext.Slab, at index: Int) -> Element { + private static func element(in slab: BridgedContext.Slab, at index: Int) -> Element { return pointer(in: slab, at: index).pointee } - private static func pointer(in slab: BridgedPassContext.Slab, at index: Int) -> UnsafeMutablePointer { + private static func pointer(in slab: BridgedContext.Slab, at index: Int) -> UnsafeMutablePointer { return UnsafeMutableRawPointer(slab.data!).assumingMemoryBound(to: Element.self) + index } - struct Iterator : IteratorProtocol { - var slab: BridgedPassContext.Slab + public struct Iterator : IteratorProtocol { + var slab: BridgedContext.Slab var index: Int - let lastSlab: BridgedPassContext.Slab + let lastSlab: BridgedContext.Slab let endIndex: Int - mutating func next() -> Element? { + public mutating func next() -> Element? { let end = (slab.data == lastSlab.data ? endIndex : slabCapacity) guard index < end else { return nil } @@ -72,21 +71,21 @@ struct Stack : CollectionLikeSequence { } } - init(_ context: some Context) { self.bridgedContext = context._bridged } + public init(_ context: some Context) { self.bridgedContext = context._bridged } - func makeIterator() -> Iterator { + public func makeIterator() -> Iterator { return Iterator(slab: firstSlab, index: 0, lastSlab: lastSlab, endIndex: endIndex) } - var first: Element? { + public var first: Element? { isEmpty ? nil : Stack.element(in: firstSlab, at: 0) } - var last: Element? { + public var last: Element? { isEmpty ? nil : Stack.element(in: lastSlab, at: endIndex &- 1) } - mutating func push(_ element: Element) { + public mutating func push(_ element: Element) { if endIndex >= Stack.slabCapacity { lastSlab = allocate(after: lastSlab) endIndex = 0 @@ -100,17 +99,17 @@ struct Stack : CollectionLikeSequence { } /// The same as `push` to provide an Array-like append API. - mutating func append(_ element: Element) { push(element) } + public mutating func append(_ element: Element) { push(element) } - mutating func append(contentsOf other: S) where S.Element == Element { + public mutating func append(contentsOf other: S) where S.Element == Element { for elem in other { append(elem) } } - var isEmpty: Bool { return endIndex == 0 } - - mutating func pop() -> Element? { + public var isEmpty: Bool { return endIndex == 0 } + + public mutating func pop() -> Element? { if isEmpty { return nil } @@ -133,12 +132,12 @@ struct Stack : CollectionLikeSequence { return elem } - mutating func removeAll() { + public mutating func removeAll() { while pop() != nil { } } /// TODO: once we have move-only types, make this a real deinit. - mutating func deinitialize() { removeAll() } + public mutating func deinitialize() { removeAll() } } extension Stack { @@ -146,7 +145,7 @@ extension Stack { /// /// TODO: Marker should be ~Escapable. struct Marker { - let slab: BridgedPassContext.Slab + let slab: BridgedContext.Slab let index: Int } diff --git a/SwiftCompilerSources/Sources/Optimizer/DataStructures/Worklist.swift b/SwiftCompilerSources/Sources/SIL/DataStructures/Worklist.swift similarity index 65% rename from SwiftCompilerSources/Sources/Optimizer/DataStructures/Worklist.swift rename to SwiftCompilerSources/Sources/SIL/DataStructures/Worklist.swift index e905d36a25322..353b38dc19509 100644 --- a/SwiftCompilerSources/Sources/Optimizer/DataStructures/Worklist.swift +++ b/SwiftCompilerSources/Sources/SIL/DataStructures/Worklist.swift @@ -10,8 +10,6 @@ // //===----------------------------------------------------------------------===// -import SIL - /// A utility for processing entities in a worklist. /// /// A `Worklist` is basically a combination of a stack and a set. @@ -20,20 +18,20 @@ import SIL /// This type should be a move-only type, but unfortunately we don't have move-only /// types yet. Therefore it's needed to call `deinitialize()` explicitly to /// destruct this data structure, e.g. in a `defer {}` block. -struct Worklist : CustomStringConvertible, NoReflectionChildren { - typealias Element = Set.Element +public struct Worklist : CustomStringConvertible, NoReflectionChildren { + public typealias Element = Set.Element private var worklist: Stack private var pushedElements: Set - init(_ context: some Context) { + public init(_ context: some Context) { self.worklist = Stack(context) self.pushedElements = Set(context) } - mutating func pop() -> Element? { return worklist.pop() } + public mutating func pop() -> Element? { return worklist.pop() } /// Pop and allow the popped element to be pushed again to the worklist. - mutating func popAndForget() -> Element? { + public mutating func popAndForget() -> Element? { if let element = worklist.pop() { pushedElements.erase(element) return element @@ -41,24 +39,24 @@ struct Worklist : CustomStringConvertible, NoReflectionChildr return nil } - mutating func pushIfNotVisited(_ element: Element) { + public mutating func pushIfNotVisited(_ element: Element) { if pushedElements.insert(element) { worklist.append(element) } } - mutating func pushIfNotVisited(contentsOf other: S) where S.Element == Element { + public mutating func pushIfNotVisited(contentsOf other: S) where S.Element == Element { for element in other { pushIfNotVisited(element) } } /// Returns true if \p element was pushed to the worklist, regardless if it's already popped or not. - func hasBeenPushed(_ element: Element) -> Bool { pushedElements.contains(element) } + public func hasBeenPushed(_ element: Element) -> Bool { pushedElements.contains(element) } - var isEmpty: Bool { worklist.isEmpty } + public var isEmpty: Bool { worklist.isEmpty } - var description: String { + public var description: String { """ worklist: \(worklist) pushed: \(pushedElements) @@ -66,20 +64,20 @@ struct Worklist : CustomStringConvertible, NoReflectionChildr } /// TODO: once we have move-only types, make this a real deinit. - mutating func deinitialize() { + public mutating func deinitialize() { pushedElements.deinitialize() worklist.deinitialize() } } -typealias BasicBlockWorklist = Worklist -typealias InstructionWorklist = Worklist -typealias SpecificInstructionWorklist = Worklist> -typealias ValueWorklist = Worklist -typealias OperandWorklist = Worklist +public typealias BasicBlockWorklist = Worklist +public typealias InstructionWorklist = Worklist +public typealias SpecificInstructionWorklist = Worklist> +public typealias ValueWorklist = Worklist +public typealias OperandWorklist = Worklist extension InstructionWorklist { - mutating func pushPredecessors(of inst: Instruction, ignoring ignoreInst: Instruction) { + public mutating func pushPredecessors(of inst: Instruction, ignoring ignoreInst: Instruction) { if let prev = inst.previous { if prev != ignoreInst { pushIfNotVisited(prev) @@ -94,7 +92,7 @@ extension InstructionWorklist { } } - mutating func pushSuccessors(of inst: Instruction, ignoring ignoreInst: Instruction) { + public mutating func pushSuccessors(of inst: Instruction, ignoring ignoreInst: Instruction) { if let succ = inst.next { if succ != ignoreInst { pushIfNotVisited(succ) @@ -111,34 +109,36 @@ extension InstructionWorklist { } /// A worklist for `Function`s. -struct FunctionWorklist { +public struct FunctionWorklist { // The current functions in the worklist. - private(set) var functions = Array() + public private(set) var functions = Array() // All functions which were ever pushed to the worklist. private var pushedFunctions = Set() - mutating func pushIfNotVisited(_ function: Function) { + public init() {} + + public mutating func pushIfNotVisited(_ function: Function) { if pushedFunctions.insert(function).inserted { functions.append(function) } } - mutating func pushIfNotVisited(contentsOf functions: S) where S.Element == Function { + public mutating func pushIfNotVisited(contentsOf functions: S) where S.Element == Function { for f in functions { pushIfNotVisited(f) } } - mutating func pop() -> Function? { + public mutating func pop() -> Function? { return functions.popLast() } } /// Like `ValueWorklist`, but allows pushing `Value`s from different functions - /// at the cost of a less efficient implementation. -struct CrossFunctionValueWorklist { +public struct CrossFunctionValueWorklist { // The current values in the worklist. private(set) var values = Array() @@ -146,27 +146,27 @@ struct CrossFunctionValueWorklist { // All values which were ever pushed to the worklist. private var pushedValues = Set(minimumCapacity: 8) - init() { + public init() { values.reserveCapacity(8) } - mutating func pop() -> Value? { + public mutating func pop() -> Value? { return values.popLast() } - mutating func pushIfNotVisited(_ value: Value) { + public mutating func pushIfNotVisited(_ value: Value) { if pushedValues.insert(ObjectIdentifier(value)).inserted { values.append(value) } } - mutating func pushIfNotVisited(contentsOf values: S) where S.Element == Value { + public mutating func pushIfNotVisited(contentsOf values: S) where S.Element == Value { for value in values { pushIfNotVisited(value) } } - func hasBeenPushed(_ value: Value) -> Bool { + public func hasBeenPushed(_ value: Value) -> Bool { return pushedValues.contains(ObjectIdentifier(value)) } } diff --git a/SwiftCompilerSources/Sources/SIL/DeclRef.swift b/SwiftCompilerSources/Sources/SIL/DeclRef.swift index 3793441e3b2b6..a41660a57cc2a 100644 --- a/SwiftCompilerSources/Sources/SIL/DeclRef.swift +++ b/SwiftCompilerSources/Sources/SIL/DeclRef.swift @@ -30,6 +30,12 @@ public struct DeclRef: CustomStringConvertible, NoReflectionChildren { public static func ==(lhs: DeclRef, rhs: DeclRef) -> Bool { lhs.bridged.isEqualTo(rhs.bridged) } + + /// Do we have enough information to determine all callees that could + /// be reached by calling the function represented by Decl? + public func calleesAreStaticallyKnowable(_ context: some Context) -> Bool { + context._bridged.calleesAreStaticallyKnowable(bridged) + } } extension DeclRef: DiagnosticArgument { diff --git a/SwiftCompilerSources/Sources/SIL/ForwardingInstruction.swift b/SwiftCompilerSources/Sources/SIL/ForwardingInstruction.swift index 174c0e30be8e9..276bef4a9ff92 100644 --- a/SwiftCompilerSources/Sources/SIL/ForwardingInstruction.swift +++ b/SwiftCompilerSources/Sources/SIL/ForwardingInstruction.swift @@ -53,7 +53,12 @@ extension ForwardingInstruction { public var forwardingOwnership: Ownership { Ownership(bridged: bridged.ForwardingInst_forwardingOwnership()) } - + + public func setForwardingOwnership(to ownership: Ownership, _ context: some MutatingContext) { + context.notifyInstructionsChanged() + bridged.ForwardingInst_setForwardingOwnership(ownership._bridged) + } + /// A forwarding instruction preserves reference counts if it has a dynamically non-trivial result in which all references are forwarded from the operand. /// /// A cast can only forward guaranteed values if it preserves reference counts. Such casts cannot release any references within their operand's value and cannot retain any references owned by their result. diff --git a/SwiftCompilerSources/Sources/SIL/Function.swift b/SwiftCompilerSources/Sources/SIL/Function.swift index d61fd310be65c..bb28fd1aab33a 100644 --- a/SwiftCompilerSources/Sources/SIL/Function.swift +++ b/SwiftCompilerSources/Sources/SIL/Function.swift @@ -94,6 +94,11 @@ final public class Function : CustomStringConvertible, HasShortDescription, Hash public var entryBlock: BasicBlock { blocks.first! } + public func appendNewBlock(_ context: some MutatingContext) -> BasicBlock { + context.notifyBranchesChanged() + return context._bridged.appendBlock(bridged).block + } + public var arguments: LazyMapSequence { entryBlock.arguments.lazy.map { $0 as! FunctionArgument } } @@ -242,6 +247,15 @@ final public class Function : CustomStringConvertible, HasShortDescription, Hash fatalError() } } + public func set(thunkKind: ThunkKind, _ context: some MutatingContext) { + context.notifyEffectsChanged() + switch thunkKind { + case .noThunk: bridged.setThunk(.IsNotThunk) + case .thunk: bridged.setThunk(.IsThunk) + case .reabstractionThunk: bridged.setThunk(.IsReabstractionThunk) + case .signatureOptimizedThunk: bridged.setThunk(.IsSignatureOptimizedThunk) + } + } public var accessorKindName: String? { guard bridged.isAccessor() else { @@ -260,6 +274,10 @@ final public class Function : CustomStringConvertible, HasShortDescription, Hash public var needsStackProtection: Bool { bridged.needsStackProtection() } + public func set(needStackProtection: Bool, _ context: some MutatingContext) { + context.notifyEffectsChanged() + bridged.setNeedStackProtection(needStackProtection) + } public var isDeinitBarrier: Bool { effects.sideEffects?.global.isDeinitBarrier ?? true @@ -285,6 +303,10 @@ final public class Function : CustomStringConvertible, HasShortDescription, Hash default: fatalError("unknown performance constraint") } } + public func set(isPerformanceConstraint: Bool, _ context: some MutatingContext) { + context.notifyEffectsChanged() + bridged.setIsPerformanceConstraint(isPerformanceConstraint) + } public enum InlineStrategy { case automatic @@ -460,8 +482,8 @@ extension Function { } } - // Only to be called by PassContext - public func _modifyEffects(_ body: (inout FunctionEffects) -> ()) { + public func modifyEffects(_ context: some MutatingContext, _ body: (inout FunctionEffects) -> ()) { + context.notifyEffectsChanged() body(&effects) } } diff --git a/SwiftCompilerSources/Sources/SIL/Instruction.swift b/SwiftCompilerSources/Sources/SIL/Instruction.swift index 7383e91ecae50..31a8c89c56df1 100644 --- a/SwiftCompilerSources/Sources/SIL/Instruction.swift +++ b/SwiftCompilerSources/Sources/SIL/Instruction.swift @@ -63,6 +63,15 @@ public class Instruction : CustomStringConvertible, Hashable { return allOperands[(allOperands.count - typeOperands.count) ..< allOperands.count] } + public final func setOperand(at index : Int, to value: Value, _ context: some MutatingContext) { + if let apply = self as? FullApplySite, apply.isCallee(operand: operands[index]) { + context.notifyCallsChanged() + } + context.notifyInstructionsChanged() + bridged.setOperand(index, value.bridged) + context.notifyInstructionChanged(self) + } + fileprivate var resultCount: Int { 0 } fileprivate func getResult(index: Int) -> Value { fatalError() } @@ -83,6 +92,11 @@ public class Instruction : CustomStringConvertible, Hashable { return Location(bridged: bridged.getLocation()) } + public final func move(before otherInstruction: Instruction, _ context: some MutatingContext) { + BridgedContext.moveInstructionBefore(bridged, otherInstruction.bridged) + context.notifyInstructionsChanged() + } + public var mayTrap: Bool { false } final public var mayHaveSideEffects: Bool { @@ -206,6 +220,12 @@ public class SingleValueInstruction : Instruction, Value { } public var isLexical: Bool { false } + + /// Replaces all uses with `replacement` and then erases the instruction. + public final func replace(with replacement: Value, _ context: some MutatingContext) { + uses.replaceAll(with: replacement, context) + context.erase(instruction: self) + } } public final class MultipleValueInstructionResult : Value, Hashable { @@ -247,6 +267,14 @@ public class MultipleValueInstruction : Instruction { fileprivate final override func getResult(index: Int) -> Value { bridged.MultipleValueInstruction_getResult(index).result } + + /// Replaces all uses with the result of `replacement` and then erases the instruction. + public final func replace(with replacement: MultipleValueInstruction, _ context: some MutatingContext) { + for (origResult, newResult) in zip(self.results, replacement.results) { + origResult.uses.replaceAll(with: newResult, context) + } + context.erase(instruction: self) + } } /// Instructions, which have a single operand (not including type-dependent operands). @@ -333,9 +361,20 @@ final public class CopyAddrInst : Instruction, SourceDestAddrInstruction { public var isTakeOfSource: Bool { bridged.CopyAddrInst_isTakeOfSrc() } + public func set(isTakeOfSource: Bool, _ context: some MutatingContext) { + context.notifyInstructionsChanged() + bridged.CopyAddrInst_setIsTakeOfSrc(isTakeOfSource) + context.notifyInstructionChanged(self) + } + public var isInitializationOfDestination: Bool { bridged.CopyAddrInst_isInitializationOfDest() } + public func set(isInitializationOfDestination: Bool, _ context: some MutatingContext) { + context.notifyInstructionsChanged() + bridged.CopyAddrInst_setIsInitializationOfDest(isInitializationOfDestination) + context.notifyInstructionChanged(self) + } } final public class ExplicitCopyAddrInst : Instruction, SourceDestAddrInstruction { @@ -563,6 +602,12 @@ final public class RebindMemoryInst : SingleValueInstruction {} public class RefCountingInst : Instruction, UnaryInstruction { public var isAtomic: Bool { bridged.RefCountingInst_getIsAtomic() } + + public final func setAtomicity(isAtomic: Bool, _ context: some MutatingContext) { + context.notifyInstructionsChanged() + bridged.RefCountingInst_setIsAtomic(isAtomic) + context.notifyInstructionChanged(self) + } } final public class StrongRetainInst : RefCountingInst { @@ -675,6 +720,11 @@ final public class LoadInst : SingleValueInstruction, LoadInstruction { public var loadOwnership: LoadOwnership { LoadOwnership(rawValue: bridged.LoadInst_getLoadOwnership())! } + public func set(ownership: LoadInst.LoadOwnership, _ context: some MutatingContext) { + context.notifyInstructionsChanged() + bridged.LoadInst_setOwnership(ownership.rawValue) + context.notifyInstructionChanged(self) + } } final public class LoadWeakInst : SingleValueInstruction, LoadInstruction {} @@ -763,6 +813,11 @@ class PointerToAddressInst : SingleValueInstruction, UnaryInstruction { } return Int(exactly: maybeAlign) } + public func set(alignment: Int?, _ context: some MutatingContext) { + context.notifyInstructionsChanged() + bridged.PointerToAddressInst_setAlignment(UInt64(alignment ?? 0)) + context.notifyInstructionChanged(self) + } } public protocol IndexingInstruction: SingleValueInstruction { @@ -896,10 +951,22 @@ final public class GlobalAddrInst : GlobalAccessInstruction, VarDeclInstruction public var dependencyToken: Value? { operands.count == 1 ? operands[0].value : nil } + + public func clearToken(_ context: some MutatingContext) { + context.notifyInstructionsChanged() + bridged.GlobalAddrInst_clearToken() + context.notifyInstructionChanged(self) + } } final public class GlobalValueInst : GlobalAccessInstruction { public var isBare: Bool { bridged.GlobalValueInst_isBare() } + + public func setIsBare(_ context: some MutatingContext) { + context.notifyInstructionsChanged() + bridged.GlobalValueInst_setIsBare() + context.notifyInstructionChanged(self) + } } final public class BaseAddrForOffsetInst : SingleValueInstruction {} @@ -1016,6 +1083,12 @@ final public class RefElementAddrInst : SingleValueInstruction, UnaryInstruction public var isImmutable: Bool { bridged.RefElementAddrInst_isImmutable() } + public func set(isImmutable: Bool, _ context: some MutatingContext) { + context.notifyInstructionsChanged() + bridged.RefElementAddrInst_setImmutable(isImmutable) + context.notifyInstructionChanged(self) + } + public var varDecl: VarDecl? { bridged.RefElementAddr_getDecl().getAs(VarDecl.self) } @@ -1127,6 +1200,17 @@ extension MarkDependenceInstruction { public var valueOrAddress: Value { valueOrAddressOperand.value } public var baseOperand: Operand { operands[1] } public var base: Value { baseOperand.value } + + public func resolveToNonEscaping(_ context: some MutatingContext) { + context.notifyInstructionsChanged() + bridged.MarkDependenceInstruction_resolveToNonEscaping() + context.notifyInstructionChanged(self) + } + public func settleToEscaping(_ context: some MutatingContext) { + context.notifyInstructionsChanged() + bridged.MarkDependenceInstruction_settleToEscaping() + context.notifyInstructionChanged(self) + } } final public class MarkDependenceInst : SingleValueInstruction, MarkDependenceInstruction { @@ -1404,6 +1488,12 @@ public class AllocRefInstBase : SingleValueInstruction, Allocation { bridged.AllocRefInstBase_canAllocOnStack() } + public final func setIsStackAllocatable(_ context: some MutatingContext) { + context.notifyInstructionsChanged() + bridged.AllocRefInstBase_setIsStackAllocatable() + context.notifyInstructionChanged(self) + } + final public var tailAllocatedCounts: OperandArray { let numTailTypes = bridged.AllocRefInstBase_getNumTailTypes() return operands[0.. Bool { return lhs.bridged.op == rhs.bridged.op } @@ -45,6 +49,12 @@ public struct Operand : CustomStringConvertible, NoReflectionChildren, Equatable public func canAccept(ownership: Ownership) -> Bool { bridged.canAcceptOwnership(ownership._bridged) } + public func changeOwnership(from: Ownership, to: Ownership, _ context: some MutatingContext) { + context.notifyInstructionsChanged() + bridged.changeOwnership(from._bridged, to._bridged) + context.notifyInstructionChanged(instruction) + } + public var description: String { "operand #\(index) of \(instruction)" } } @@ -185,6 +195,12 @@ extension Sequence where Element == Operand { public func users(ofType: I.Type) -> LazyMapSequence, I> { self.lazy.filter{ $0.instruction is I }.lazy.map { $0.instruction as! I } } + + public func replaceAll(with replacement: Value, _ context: some MutatingContext) { + for use in self { + use.set(to: replacement, context) + } + } } extension Value { diff --git a/SwiftCompilerSources/Sources/SIL/Registration.swift b/SwiftCompilerSources/Sources/SIL/Registration.swift index d8f352762e129..103c10390c9da 100644 --- a/SwiftCompilerSources/Sources/SIL/Registration.swift +++ b/SwiftCompilerSources/Sources/SIL/Registration.swift @@ -13,6 +13,11 @@ import Basic import SILBridging +public func registerSIL() { + registerSILClasses() + registerUtilities() +} + private func register(_ cl: T.Type) { "\(cl)"._withBridgedStringRef { nameStr in let metatype = unsafeBitCast(cl, to: SwiftMetatype.self) @@ -20,7 +25,7 @@ private func register(_ cl: T.Type) { } } -public func registerSILClasses() { +private func registerSILClasses() { Function.register() register(BasicBlock.self) register(GlobalVariable.self) @@ -262,3 +267,8 @@ public func registerSILClasses() { register(MergeIsolationRegionInst.self) register(IgnoredUseInst.self) } + +private func registerUtilities() { + registerVerifier() + registerPhiUpdater() +} diff --git a/SwiftCompilerSources/Sources/SIL/Utilities/AccessUtils.swift b/SwiftCompilerSources/Sources/SIL/Utilities/AccessUtils.swift index a64827e2cecf6..546d5c7c30893 100644 --- a/SwiftCompilerSources/Sources/SIL/Utilities/AccessUtils.swift +++ b/SwiftCompilerSources/Sources/SIL/Utilities/AccessUtils.swift @@ -870,3 +870,11 @@ extension Function { return nil } } + +let getAccessBaseTest = Test("swift_get_access_base") { + function, arguments, context in + let address = arguments.takeValue() + print("Address: \(address)") + let base = address.accessBase + print("Base: \(base)") +} diff --git a/SwiftCompilerSources/Sources/Optimizer/Utilities/BorrowUtils.swift b/SwiftCompilerSources/Sources/SIL/Utilities/BorrowUtils.swift similarity index 90% rename from SwiftCompilerSources/Sources/Optimizer/Utilities/BorrowUtils.swift rename to SwiftCompilerSources/Sources/SIL/Utilities/BorrowUtils.swift index c1b0c4daa6376..069883ce1ee91 100644 --- a/SwiftCompilerSources/Sources/Optimizer/Utilities/BorrowUtils.swift +++ b/SwiftCompilerSources/Sources/SIL/Utilities/BorrowUtils.swift @@ -130,8 +130,6 @@ // patterns). // ===----------------------------------------------------------------------===// -import SIL - /// A scoped instruction that borrows one or more operands. /// /// If this instruction produces a borrowed value, then BeginBorrowValue(resultOf: self) != nil. @@ -151,7 +149,7 @@ import SIL /// operand. /// /// TODO: replace BorrowIntroducingInstruction with this. -enum BorrowingInstruction : CustomStringConvertible, Hashable { +public enum BorrowingInstruction : CustomStringConvertible, Hashable { case beginBorrow(BeginBorrowInst) case borrowedFrom(BorrowedFromInst) case storeBorrow(StoreBorrowInst) @@ -160,7 +158,7 @@ enum BorrowingInstruction : CustomStringConvertible, Hashable { case markDependence(MarkDependenceInst) case startAsyncLet(BuiltinInst) - init?(_ inst: Instruction) { + public init?(_ inst: Instruction) { switch inst { case let bbi as BeginBorrowInst: self = .beginBorrow(bbi) @@ -185,7 +183,7 @@ enum BorrowingInstruction : CustomStringConvertible, Hashable { } } - var instruction: Instruction { + public var instruction: Instruction { switch self { case .beginBorrow(let bbi): return bbi @@ -204,7 +202,7 @@ enum BorrowingInstruction : CustomStringConvertible, Hashable { } } - var innerValue: Value? { + public var innerValue: Value? { if let dependent = dependentValue { return dependent } @@ -214,7 +212,7 @@ enum BorrowingInstruction : CustomStringConvertible, Hashable { /// Returns non-nil if this borrowing instruction produces an guaranteed dependent value and does not have immediate /// scope-ending uses. Finding the borrow scope in such cases requires recursively following uses of the guaranteed /// value. - var dependentValue: Value? { + public var dependentValue: Value? { switch self { case .borrowedFrom(let bfi): let phi = bfi.borrowedPhi @@ -233,7 +231,7 @@ enum BorrowingInstruction : CustomStringConvertible, Hashable { } /// If this is valid, then visitScopeEndingOperands succeeds. - var scopedValue: Value? { + public var scopedValue: Value? { switch self { case .beginBorrow, .storeBorrow: return instruction as! SingleValueInstruction @@ -271,7 +269,7 @@ enum BorrowingInstruction : CustomStringConvertible, Hashable { /// /// TODO: For instructions that are not a BeginBorrowValue, verify that scope ending instructions exist on all /// paths. These instructions should be complete after SILGen and never cloned to produce phis. - func visitScopeEndingOperands(_ context: Context, visitor: @escaping (Operand) -> WalkResult) -> WalkResult { + public func visitScopeEndingOperands(_ context: Context, visitor: @escaping (Operand) -> WalkResult) -> WalkResult { guard let val = scopedValue else { return .abortWalk } @@ -326,7 +324,7 @@ extension BorrowingInstruction { } } - var description: String { instruction.description } + public var description: String { instruction.description } } /// A value that introduces a borrow scope: @@ -340,7 +338,7 @@ extension BorrowingInstruction { /// one of the yielded values. In any case, the scope ending operands /// are on the end_apply or abort_apply instructions that use the /// token. -enum BeginBorrowValue { +public enum BeginBorrowValue { case beginBorrow(BeginBorrowInst) case loadBorrow(LoadBorrowInst) case beginApply(Value) @@ -348,7 +346,7 @@ enum BeginBorrowValue { case functionArgument(FunctionArgument) case reborrow(Phi) - init?(_ value: Value) { + public init?(_ value: Value) { switch value { case let bbi as BeginBorrowInst: self = .beginBorrow(bbi) @@ -369,7 +367,7 @@ enum BeginBorrowValue { } } - var value: Value { + public var value: Value { switch self { case .beginBorrow(let bbi): return bbi case .loadBorrow(let lbi): return lbi @@ -380,7 +378,7 @@ enum BeginBorrowValue { } } - init?(using operand: Operand) { + public init?(using operand: Operand) { switch operand.instruction { case is BeginBorrowInst, is LoadBorrowInst: let inst = operand.instruction as! SingleValueInstruction @@ -398,7 +396,7 @@ enum BeginBorrowValue { } } - init?(resultOf borrowInstruction: BorrowingInstruction) { + public init?(resultOf borrowInstruction: BorrowingInstruction) { switch borrowInstruction { case let .beginBorrow(beginBorrow): self.init(beginBorrow) @@ -412,7 +410,7 @@ enum BeginBorrowValue { } } - var hasLocalScope: Bool { + public var hasLocalScope: Bool { switch self { case .beginBorrow, .loadBorrow, .beginApply, .reborrow, .uncheckOwnershipConversion: return true @@ -425,7 +423,7 @@ enum BeginBorrowValue { // load_borrow. // // Return nil for begin_apply and reborrow, which need special handling. - var baseOperand: Operand? { + public var baseOperand: Operand? { switch self { case let .beginBorrow(beginBorrow): return beginBorrow.operand @@ -438,7 +436,7 @@ enum BeginBorrowValue { /// The EndBorrows, reborrows (phis), and consumes (of closures) /// that end the local borrow scope. Empty if hasLocalScope is false. - var scopeEndingOperands: LazyFilterSequence { + public var scopeEndingOperands: LazyFilterSequence { switch self { case let .beginApply(value): return (value.definingInstruction @@ -451,28 +449,8 @@ enum BeginBorrowValue { } } -/// Compute the live range for the borrow scopes of a guaranteed value. This returns a separate instruction range for -/// each of the value's borrow introducers. -/// -/// TODO: This should return a single multiply-defined instruction range. -func computeBorrowLiveRange(for value: Value, _ context: FunctionPassContext) - -> SingleInlineArray<(BeginBorrowValue, InstructionRange)> { - assert(value.ownership == .guaranteed) - - var ranges = SingleInlineArray<(BeginBorrowValue, InstructionRange)>() - // If introducers is empty, then the dependence is on a trivial value, so - // there is no ownership range. - for beginBorrow in value.getBorrowIntroducers(context) { - /// FIXME: Remove calls to computeKnownLiveness() as soon as lifetime completion runs immediately after - /// SILGen. Instead, this should compute linear liveness for borrowed value by switching over BeginBorrowValue, just - /// like LifetimeDependence.Scope.computeRange(). - ranges.push((beginBorrow, computeKnownLiveness(for: beginBorrow.value, context))) - } - return ranges -} - extension Value { - var lookThroughBorrowedFrom: Value { + public var lookThroughBorrowedFrom: Value { if let bfi = self as? BorrowedFromInst { return bfi.borrowedValue.lookThroughBorrowedFrom } @@ -480,20 +458,20 @@ extension Value { } } -struct BorrowIntroducers : CollectionLikeSequence { +public struct BorrowIntroducers : CollectionLikeSequence { let initialValue: Value let context: Ctxt - func makeIterator() -> EnclosingValueIterator { + public func makeIterator() -> EnclosingValueIterator { EnclosingValueIterator(forBorrowIntroducers: initialValue, context) } } -struct EnclosingValues : CollectionLikeSequence { +public struct EnclosingValues : CollectionLikeSequence { let initialValue: Value let context: Ctxt - func makeIterator() -> EnclosingValueIterator { + public func makeIterator() -> EnclosingValueIterator { EnclosingValueIterator(forEnclosingValues: initialValue, context) } } @@ -501,7 +479,7 @@ struct EnclosingValues : CollectionLikeSequence { // This iterator must be a class because we need a deinit. // It shouldn't be a performance problem because the optimizer should always be able to stack promote the iterator. // TODO: Make it a struct once this is possible with non-copyable types. -final class EnclosingValueIterator : IteratorProtocol { +public final class EnclosingValueIterator : IteratorProtocol { var worklist: ValueWorklist init(forBorrowIntroducers value: Value, _ context: some Context) { @@ -535,7 +513,7 @@ final class EnclosingValueIterator : IteratorProtocol { worklist.deinitialize() } - func next() -> Value? { + public func next() -> Value? { while let value = worklist.pop() { switch value.ownership { case .none, .unowned: @@ -584,7 +562,9 @@ extension Value { /// %field = ref_element_addr %first // (none) /// %load = load_borrow %field : $*C // %load /// - func getBorrowIntroducers(_ context: Ctxt) -> LazyMapSequence, BeginBorrowValue> { + public func getBorrowIntroducers( + _ context: Ctxt + ) -> LazyMapSequence, BeginBorrowValue> { BorrowIntroducers(initialValue: self, context: context).lazy.map { BeginBorrowValue($0)! } } @@ -625,15 +605,24 @@ extension Value { /// bb1(%outerReborrow : @reborrow, // %0 /// %innerReborrow : @reborrow) // %outerReborrow /// - func getEnclosingValues(_ context: Ctxt) -> EnclosingValues { + public func getEnclosingValues(_ context: Ctxt) -> EnclosingValues { EnclosingValues(initialValue: self, context: context) } + + public var lookThroughBorrowedFromUser: Value { + for use in uses { + if let bfi = use.forwardingBorrowedFromUser { + return bfi + } + } + return self + } } extension Phi { /// The inner adjacent phis of this outer "enclosing" phi. /// These keep the enclosing (outer adjacent) phi alive. - var innerAdjacentPhis: LazyMapSequence>, Phi> { + public var innerAdjacentPhis: LazyMapSequence>, Phi> { value.uses.lazy.compactMap { use in if let bfi = use.instruction as? BorrowedFromInst, use.index != 0 @@ -647,7 +636,7 @@ extension Phi { /// Gathers enclosing values by visiting predecessor blocks. /// Only used for updating borrowed-from instructions and for verification. -func gatherEnclosingValuesFromPredecessors( +public func gatherEnclosingValuesFromPredecessors( for phi: Phi, in enclosingValues: inout Stack, _ context: some Context @@ -669,7 +658,7 @@ func gatherEnclosingValuesFromPredecessors( extension BasicBlock { // Returns either the `incomingEnclosingValue` or an adjacent phi in the successor block. - func getEnclosingValueInSuccessor(ofIncoming incomingEnclosingValue: Value) -> Value { + public func getEnclosingValueInSuccessor(ofIncoming incomingEnclosingValue: Value) -> Value { let branch = terminator as! BranchInst if let incomingEV = branch.operands.first(where: { branchOp in // Only if the lifetime of `branchOp` ends at the branch (either because it's a reborrow or an owned value), @@ -697,7 +686,7 @@ extension BasicBlock { } } -let borrowIntroducersTest = FunctionTest("borrow_introducers") { +let borrowIntroducersTest = Test("borrow_introducers") { function, arguments, context in let value = arguments.takeValue() print(function) @@ -707,7 +696,7 @@ let borrowIntroducersTest = FunctionTest("borrow_introducers") { } } -let enclosingValuesTest = FunctionTest("enclosing_values") { +let enclosingValuesTest = Test("enclosing_values") { function, arguments, context in let value = arguments.takeValue() print(function) @@ -721,14 +710,3 @@ let enclosingValuesTest = FunctionTest("enclosing_values") { } } -extension Value { - var lookThroughBorrowedFromUser: Value { - for use in uses { - if let bfi = use.forwardingBorrowedFromUser { - return bfi - } - } - return self - } -} - diff --git a/SwiftCompilerSources/Sources/SIL/Utilities/CMakeLists.txt b/SwiftCompilerSources/Sources/SIL/Utilities/CMakeLists.txt index ef985c9c68ab4..f39a2a89ae0e3 100644 --- a/SwiftCompilerSources/Sources/SIL/Utilities/CMakeLists.txt +++ b/SwiftCompilerSources/Sources/SIL/Utilities/CMakeLists.txt @@ -8,8 +8,14 @@ swift_compiler_sources(SIL AccessUtils.swift + BorrowUtils.swift + ForwardingUtils.swift + PhiUpdater.swift SequenceUtilities.swift SmallProjectionPath.swift + SSAUpdater.swift + Test.swift WalkUtils.swift + Verifier.swift ) diff --git a/SwiftCompilerSources/Sources/Optimizer/Utilities/ForwardingUtils.swift b/SwiftCompilerSources/Sources/SIL/Utilities/ForwardingUtils.swift similarity index 87% rename from SwiftCompilerSources/Sources/Optimizer/Utilities/ForwardingUtils.swift rename to SwiftCompilerSources/Sources/SIL/Utilities/ForwardingUtils.swift index 5877b5726c0fc..03b0e3b422830 100644 --- a/SwiftCompilerSources/Sources/Optimizer/Utilities/ForwardingUtils.swift +++ b/SwiftCompilerSources/Sources/SIL/Utilities/ForwardingUtils.swift @@ -16,8 +16,6 @@ /// is part of a forward-extended lifetime that has a pointer escape. //===----------------------------------------------------------------------===// -import SIL - private let verbose = false private func log(_ message: @autoclosure () -> String) { @@ -36,7 +34,7 @@ private func log(_ message: @autoclosure () -> String) { /// Allocation. Then add a `Value.hasPointerEscapingUse` property that /// performs the use-def walk to pickup the flags. Then only call into /// this def-use walk to initially set the flags. -func findPointerEscapingUse(of value: Value) -> Bool { +public func findPointerEscapingUse(of value: Value) -> Bool { value.bridged.findPointerEscape() } @@ -100,7 +98,7 @@ func findPointerEscapingUse(of value: Value) -> Bool { /// This walker is used to query basic lifetime attributes on values, /// such as "escaping" or "lexical". It must be precise for /// correctness and is performance critical. -protocol ForwardingUseDefWalker { +public protocol ForwardingUseDefWalker { associatedtype PathContext mutating func introducer(_ value: Value, _ path: PathContext) -> WalkResult @@ -113,10 +111,10 @@ protocol ForwardingUseDefWalker { } extension ForwardingUseDefWalker { - mutating func walkUp(value: Value, _ path: PathContext) -> WalkResult { + public mutating func walkUp(value: Value, _ path: PathContext) -> WalkResult { walkUpDefault(forwarded: value, path) } - mutating func walkUpDefault(forwarded value: Value, _ path: PathContext) + public mutating func walkUpDefault(forwarded value: Value, _ path: PathContext) -> WalkResult { if let inst = value.forwardingInstruction, !inst.forwardedOperands.isEmpty { return walkUp(instruction: inst, path) @@ -126,7 +124,7 @@ extension ForwardingUseDefWalker { } return introducer(value, path) } - mutating func walkUp(instruction: ForwardingInstruction, _ path: PathContext) + public mutating func walkUp(instruction: ForwardingInstruction, _ path: PathContext) -> WalkResult { for operand in instruction.forwardedOperands { if needWalk(for: operand.value, path) { @@ -137,7 +135,7 @@ extension ForwardingUseDefWalker { } return .continueWalk } - mutating func walkUp(phi: Phi, _ path: PathContext) -> WalkResult { + public mutating func walkUp(phi: Phi, _ path: PathContext) -> WalkResult { for operand in phi.incomingOperands { if needWalk(for: operand.value, path) { if walkUp(value: operand.value, path) == .abortWalk { @@ -151,7 +149,7 @@ extension ForwardingUseDefWalker { // This conveniently gathers all forward introducers and deinitializes // visitedValues before the caller has a chance to recurse. -func gatherLifetimeIntroducers(for value: Value, _ context: Context) -> [Value] { +public func gatherLifetimeIntroducers(for value: Value, _ context: Context) -> [Value] { var introducers: [Value] = [] var walker = VisitLifetimeIntroducers(context) { introducers.append($0) @@ -163,8 +161,8 @@ func gatherLifetimeIntroducers(for value: Value, _ context: Context) -> [Value] } // TODO: visitor can be nonescaping when we have borrowed properties. -func visitLifetimeIntroducers(for value: Value, _ context: Context, - visitor: @escaping (Value) -> WalkResult) +public func visitLifetimeIntroducers(for value: Value, _ context: Context, + visitor: @escaping (Value) -> WalkResult) -> WalkResult { var walker = VisitLifetimeIntroducers(context, visitor: visitor) defer { walker.visitedValues.deinitialize() } @@ -191,11 +189,11 @@ private struct VisitLifetimeIntroducers : ForwardingUseDefWalker { } } -enum ForwardingUseResult: CustomStringConvertible { +public enum ForwardingUseResult: CustomStringConvertible { case operand(Operand) case deadValue(Value, Operand?) - var description: String { + public var description: String { switch self { case .operand(let operand): return operand.description @@ -220,7 +218,7 @@ enum ForwardingUseResult: CustomStringConvertible { /// Start walking: /// walkDown(root: Value) /// -protocol ForwardingDefUseWalker { +public protocol ForwardingDefUseWalker { /// Minimally, check a ValueSet. This walker may traverse chains of /// aggregation and destructuring by default. Implementations may /// handle phis. @@ -249,16 +247,16 @@ protocol ForwardingDefUseWalker { extension ForwardingDefUseWalker { /// Start walking - mutating func walkDown(root: Value) -> WalkResult { + public mutating func walkDown(root: Value) -> WalkResult { walkDownUses(of: root, using: nil) } - mutating func walkDownUses(of value: Value, using operand: Operand?) + public mutating func walkDownUses(of value: Value, using operand: Operand?) -> WalkResult { return walkDownUsesDefault(forwarding: value, using: operand) } - mutating func walkDownUsesDefault(forwarding value: Value, + public mutating func walkDownUsesDefault(forwarding value: Value, using operand: Operand?) -> WalkResult { if !needWalk(for: value) { @@ -277,11 +275,11 @@ extension ForwardingDefUseWalker { return .continueWalk } - mutating func walkDown(operand: Operand) -> WalkResult { + public mutating func walkDown(operand: Operand) -> WalkResult { walkDownDefault(forwarding: operand) } - mutating func walkDownDefault(forwarding operand: Operand) -> WalkResult { + public mutating func walkDownDefault(forwarding operand: Operand) -> WalkResult { if let inst = operand.instruction as? ForwardingInstruction { let singleOper = inst.singleForwardedOperand if singleOper == nil || singleOper! == operand { @@ -304,7 +302,7 @@ extension ForwardingDefUseWalker { /// /// TODO: make the visitor non-escaping once Swift supports stored /// non-escaping closures. -func visitForwardedUses(introducer: Value, _ context: Context, +public func visitForwardedUses(introducer: Value, _ context: Context, visitor: @escaping (ForwardingUseResult) -> WalkResult) -> WalkResult { var useVisitor = VisitForwardedUses(visitor: visitor, context) @@ -345,29 +343,29 @@ private struct VisitForwardedUses : ForwardingDefUseWalker { /// This is a subset of the functionality in LifetimeDependenceDefUseWalker, but significantly simpler. This avoids /// traversing lifetime dependencies that do not propagate context. For example, a mark_dependence on a closure extends /// its lifetime but cannot introduce any new uses of the closure context. -struct NonEscapingClosureDefUseWalker { +public struct NonEscapingClosureDefUseWalker { let context: Context var visitedValues: ValueSet - var applyOperandStack: Stack + public var applyOperandStack: Stack /// `visitor` takes an operand whose instruction is always a FullApplySite. - init(_ context: Context) { + public init(_ context: Context) { self.context = context self.visitedValues = ValueSet(context) self.applyOperandStack = Stack(context) } - mutating func deinitialize() { + public mutating func deinitialize() { visitedValues.deinitialize() applyOperandStack.deinitialize() } - mutating func walkDown(closure: PartialApplyInst) -> WalkResult { + public mutating func walkDown(closure: PartialApplyInst) -> WalkResult { assert(!closure.mayEscape) return walkDownUses(of: closure, using: nil) } - mutating func closureContextLeafUse(of operand: Operand) -> WalkResult { + public mutating func closureContextLeafUse(of operand: Operand) -> WalkResult { switch operand.instruction { case is FullApplySite: applyOperandStack.push(operand) @@ -388,11 +386,11 @@ struct NonEscapingClosureDefUseWalker { } extension NonEscapingClosureDefUseWalker: ForwardingDefUseWalker { - mutating func needWalk(for value: Value) -> Bool { + public mutating func needWalk(for value: Value) -> Bool { visitedValues.insert(value) } - mutating func nonForwardingUse(of operand: Operand) -> WalkResult { + public mutating func nonForwardingUse(of operand: Operand) -> WalkResult { // Nonescaping closures may be moved, copied, or borrowed. switch operand.instruction { case let transition as OwnershipTransitionInstruction: @@ -405,12 +403,12 @@ extension NonEscapingClosureDefUseWalker: ForwardingDefUseWalker { } } - mutating func deadValue(_ value: Value, using operand: Operand?) -> WalkResult { + public mutating func deadValue(_ value: Value, using operand: Operand?) -> WalkResult { return .continueWalk } } -let forwardingUseDefTest = FunctionTest("forwarding_use_def_test") { +let forwardingUseDefTest = Test("forwarding_use_def_test") { function, arguments, context in let value = arguments.takeValue() for introducer in gatherLifetimeIntroducers(for: value, context) { @@ -418,7 +416,7 @@ let forwardingUseDefTest = FunctionTest("forwarding_use_def_test") { } } -let forwardingDefUseTest = FunctionTest("forwarding_def_use_test") { +let forwardingDefUseTest = Test("forwarding_def_use_test") { function, arguments, context in let value = arguments.takeValue() _ = visitForwardedUses(introducer: value, context) { useResult in diff --git a/SwiftCompilerSources/Sources/Optimizer/Utilities/PhiUpdater.swift b/SwiftCompilerSources/Sources/SIL/Utilities/PhiUpdater.swift similarity index 84% rename from SwiftCompilerSources/Sources/Optimizer/Utilities/PhiUpdater.swift rename to SwiftCompilerSources/Sources/SIL/Utilities/PhiUpdater.swift index 9b0a8ccc803d4..081f14b88d18d 100644 --- a/SwiftCompilerSources/Sources/Optimizer/Utilities/PhiUpdater.swift +++ b/SwiftCompilerSources/Sources/SIL/Utilities/PhiUpdater.swift @@ -10,23 +10,22 @@ // //===----------------------------------------------------------------------===// -import SIL -import OptimizerBridging +import SILBridging /// Updates the reborrow flags and the borrowed-from instructions for all guaranteed phis in `function`. -func updateGuaranteedPhis(in function: Function, _ context: some MutatingContext) { +public func updateGuaranteedPhis(in function: Function, _ context: some MutatingContext) { updateReborrowFlags(in: function, context) updateBorrowedFrom(in: function, context) } /// Updates the reborrow flags and the borrowed-from instructions for all `phis`. -func updateGuaranteedPhis(phis: some Sequence, _ context: some MutatingContext) { +public func updateGuaranteedPhis(phis: some Sequence, _ context: some MutatingContext) { updateReborrowFlags(for: phis, context) updateBorrowedFrom(for: phis, context) } /// Update all borrowed-from instructions in the `function` -func updateBorrowedFrom(in function: Function, _ context: some MutatingContext) { +public func updateBorrowedFrom(in function: Function, _ context: some MutatingContext) { if !function.hasOwnership { return } @@ -44,7 +43,7 @@ func updateBorrowedFrom(in function: Function, _ context: some MutatingContext) } /// Update borrowed-from instructions for a set of phi arguments. -func updateBorrowedFrom(for phis: some Sequence, _ context: some MutatingContext) { +public func updateBorrowedFrom(for phis: some Sequence, _ context: some MutatingContext) { for phi in phis { if !phi.value.parentFunction.hasOwnership { return @@ -67,7 +66,7 @@ func updateBorrowedFrom(for phis: some Sequence, _ context: some MutatingCo } /// Updates the reborrow flags for all guaranteed phis in `function`. -func updateReborrowFlags(in function: Function, _ context: some MutatingContext) { +public func updateReborrowFlags(in function: Function, _ context: some MutatingContext) { if !function.hasOwnership { return } @@ -90,7 +89,7 @@ func updateReborrowFlags(in function: Function, _ context: some MutatingContext) /// by cutting off the control flow before an `end_borrow`, the re-borrow flags still have to remain /// without the possibility to re-calculate them from the (now missing) `end_borrow`. /// -func updateReborrowFlags(for phis: some Sequence, _ context: some MutatingContext) { +public func updateReborrowFlags(for phis: some Sequence, _ context: some MutatingContext) { if let phi = phis.first(where: { phi in true }), !phi.value.parentFunction.hasOwnership { return } @@ -160,7 +159,7 @@ private func createEmptyBorrowedFrom(for phi: Phi, _ context: some MutatingConte /// use(%1) /// ``` /// -func replacePhiWithIncomingValue(phi: Phi, _ context: some MutatingContext) -> Bool { +public func replacePhiWithIncomingValue(phi: Phi, _ context: some MutatingContext) -> Bool { if phi.predecessors.isEmpty { return false } @@ -207,7 +206,7 @@ func replacePhiWithIncomingValue(phi: Phi, _ context: some MutatingContext) -> B /// /// It's not needed to run this utility if SSAUpdater is used to create a _new_ OSSA liverange. /// -func replacePhisWithIncomingValues(phis: [Phi], _ context: some MutatingContext) { +public func replacePhisWithIncomingValues(phis: [Phi], _ context: some MutatingContext) { var currentPhis = phis // Do this in a loop because replacing one phi might open up the opportunity for another phi // and the order of phis in the array can be arbitrary. @@ -228,14 +227,14 @@ func replacePhisWithIncomingValues(phis: [Phi], _ context: some MutatingContext) func registerPhiUpdater() { BridgedUtilities.registerPhiUpdater( // updateAllGuaranteedPhis - { (bridgedCtxt: BridgedPassContext, bridgedFunction: BridgedFunction) in - let context = FunctionPassContext(_bridged: bridgedCtxt) + { (bridgedCtxt: BridgedContext, bridgedFunction: BridgedFunction) in + let context = PhiUpdaterContext(_bridged: bridgedCtxt) let function = bridgedFunction.function; updateGuaranteedPhis(in: function, context) }, // updateGuaranteedPhis - { (bridgedCtxt: BridgedPassContext, bridgedPhiArray: BridgedArrayRef) in - let context = FunctionPassContext(_bridged: bridgedCtxt) + { (bridgedCtxt: BridgedContext, bridgedPhiArray: BridgedArrayRef) in + let context = PhiUpdaterContext(_bridged: bridgedCtxt) var guaranteedPhis = Stack(context) defer { guaranteedPhis.deinitialize() } bridgedPhiArray.withElements(ofType: BridgedValue.self) { @@ -249,8 +248,8 @@ func registerPhiUpdater() { updateGuaranteedPhis(phis: guaranteedPhis, context) }, // replacePhisWithIncomingValues - { (bridgedCtxt: BridgedPassContext, bridgedPhiArray: BridgedArrayRef) in - let context = FunctionPassContext(_bridged: bridgedCtxt) + { (bridgedCtxt: BridgedContext, bridgedPhiArray: BridgedArrayRef) in + let context = PhiUpdaterContext(_bridged: bridgedCtxt) var phis = [Phi]() bridgedPhiArray.withElements(ofType: BridgedValue.self) { phis = $0.map { Phi($0.value)! } @@ -258,13 +257,9 @@ func registerPhiUpdater() { replacePhisWithIncomingValues(phis: phis, context) } ) -} - -/// This pass is only used for testing. -/// In the regular pipeline it's not needed because optimization passes must make sure that borrowed-from -/// instructions are updated once the pass finishes. -let updateBorrowedFromPass = FunctionPass(name: "update-borrowed-from") { - (function: Function, context: FunctionPassContext) in - updateBorrowedFrom(in: function, context) + struct PhiUpdaterContext: MutatingContext { + let _bridged: BridgedContext + public let notifyInstructionChanged: (Instruction) -> () = { inst in } + } } diff --git a/SwiftCompilerSources/Sources/Optimizer/Utilities/SSAUpdater.swift b/SwiftCompilerSources/Sources/SIL/Utilities/SSAUpdater.swift similarity index 78% rename from SwiftCompilerSources/Sources/Optimizer/Utilities/SSAUpdater.swift rename to SwiftCompilerSources/Sources/SIL/Utilities/SSAUpdater.swift index 60e2803d34ac0..6feaf4544b3c6 100644 --- a/SwiftCompilerSources/Sources/Optimizer/Utilities/SSAUpdater.swift +++ b/SwiftCompilerSources/Sources/SIL/Utilities/SSAUpdater.swift @@ -10,26 +10,23 @@ // //===----------------------------------------------------------------------===// -import SIL -import OptimizerBridging +import SILBridging /// Utility for updating SSA for a set of SIL instructions defined in multiple blocks. -struct SSAUpdater { +public struct SSAUpdater { let context: Context - init(function: Function, type: Type, ownership: Ownership, - _ context: Context) { + public init(function: Function, type: Type, ownership: Ownership, _ context: Context) { self.context = context - context._bridged.SSAUpdater_initialize(function.bridged, type.bridged, - ownership._bridged) + context._bridged.SSAUpdater_initialize(function.bridged, type.bridged, ownership._bridged) } - mutating func addAvailableValue(_ value: Value, in block: BasicBlock) { + public mutating func addAvailableValue(_ value: Value, in block: BasicBlock) { context._bridged.SSAUpdater_addAvailableValue(block.bridged, value.bridged) } /// Construct SSA for a value that is live at the *end* of a basic block. - mutating func getValue(atEndOf block: BasicBlock) -> Value { + public mutating func getValue(atEndOf block: BasicBlock) -> Value { context.notifyInstructionsChanged() return context._bridged.SSAUpdater_getValueAtEndOfBlock(block.bridged).value } @@ -46,12 +43,12 @@ struct SSAUpdater { /// cond_br bb2, bb3 /// /// In this case we need to insert a phi argument in bb2, merging %1 and %2. - mutating func getValue(inMiddleOf block: BasicBlock) -> Value { + public mutating func getValue(inMiddleOf block: BasicBlock) -> Value { context.notifyInstructionsChanged() return context._bridged.SSAUpdater_getValueInMiddleOfBlock(block.bridged).value } - var insertedPhis: [Phi] { + public var insertedPhis: [Phi] { var phis = [Phi]() let numPhis = context._bridged.SSAUpdater_getNumInsertedPhis() phis.reserveCapacity(numPhis) diff --git a/SwiftCompilerSources/Sources/Optimizer/Utilities/Test.swift b/SwiftCompilerSources/Sources/SIL/Utilities/Test.swift similarity index 66% rename from SwiftCompilerSources/Sources/Optimizer/Utilities/Test.swift rename to SwiftCompilerSources/Sources/SIL/Utilities/Test.swift index bba9f2d9ac4dc..ffa25078207e7 100644 --- a/SwiftCompilerSources/Sources/Optimizer/Utilities/Test.swift +++ b/SwiftCompilerSources/Sources/SIL/Utilities/Test.swift @@ -10,42 +10,25 @@ // //===----------------------------------------------------------------------===// // -// TO ADD A NEW TEST, just add a new FunctionTest instance. +// TO ADD A NEW TEST, just add a new Test instance. // - In the source file containing the functionality you want to test: -// let myNewTest = -// FunctionTest("my_new_test") { function, arguments, context in +// let myNewTest = Test("my_new_test") { function, arguments, context in // } -// - In SwiftCompilerSources/Sources/SIL/Test.swift's registerOptimizerTests +// - In SwiftCompilerSources/Sources/SIL/Test.swift's registerTests // function, add a new argument to the variadic function: -// registerFunctionTests(..., myNewTest) -// -//===----------------------------------------------------------------------===// -// -// TO TROUBLESHOOT A NEW TEST, consider the following scenarios: -// - PROBLEM: The test isn't running on PLATFORM and the failure says -// -// Found no test named my_new_test. -// -// SOLUTION: Is this a platform one that doesn't use SwiftCompilerSources -// (e.g. Windows)? Then add -// -// // REQUIRES: swift_in_compiler -// -// to the test file. -// EXPLANATION: The tests written within SwiftCompilerSources only get built -// and registered on platforms where the SwiftCompilerSources are -// built and used. +// registerTests(..., myNewTest) // //===----------------------------------------------------------------------===// // // Provides a mechanism for writing tests against compiler code in the context -// of a function. The goal is to get the same effect as calling a function and +// of a function. The goal is to get the same effect as calling a function and // checking its output. // -// This is done via the specify_test instruction. Using one or more instances +// This is done via the specify_test instruction. Using one or more instances // of it in your test case's SIL function, you can specify which test (instance -// of FunctionTest) should be run and what arguments should be provided to it. -// For full details of the specify_test instruction's grammar, see SIL.rst. +// of Test) should be run and what arguments should be provided to it. +// For full details of the specify_test instruction's grammar, +// see doc/SIL/Instructions.md. // // The test grabs the arguments it expects out of the TestArguments instance // it is provided. It calls some function or functions. It then prints out @@ -59,8 +42,7 @@ // // and // -// let myNeatoUtilityTest = -// FunctionTest("my_neato_utility") { function, arguments, test in +// let myNeatoUtilityTest = Test("my_neato_utility") { function, arguments, test in // // The code here is described in detail below. // // See 4). // let count = arguments.takeInt() @@ -82,9 +64,9 @@ // specify_test "my_neato_utility 43 %2 @function[other_fun]" // ... // } -// 3) TestRunner finds the FunctionTest instance myNeatoUtilityTest registered +// 3) TestRunner finds the Test instance myNeatoUtilityTest registered // under the name "my_neato_utility", and calls run() on it, passing the -// passing first the function, last the FunctionTest instance, AND in the +// passing first the function, last the Test instance, AND in the // middle, most importantly a TestArguments instance that contains // // (43 : Int, someValue : Value, other_fun : Function) @@ -108,23 +90,29 @@ //===----------------------------------------------------------------------===// import Basic -import SIL import SILBridging -import OptimizerBridging /// The primary interface to in-IR tests. -struct FunctionTest { +public struct Test { let name: String - let invocation: FunctionTestInvocation + let invocation: TestInvocation - public init(_ name: String, invocation: @escaping FunctionTestInvocation) { + public init(_ name: String, invocation: @escaping TestInvocation) { self.name = name self.invocation = invocation } } -/// The type of the closure passed to a FunctionTest. -typealias FunctionTestInvocation = @convention(thin) (Function, TestArguments, FunctionPassContext) -> () +/// The type of the closure passed to a Test. +public typealias TestInvocation = @convention(thin) (Function, TestArguments, TestContext) -> () + + +public struct TestContext: MutatingContext { + public let _bridged: BridgedContext + public let notifyInstructionChanged: (Instruction) -> () = { inst in } + + fileprivate init(bridged: BridgedContext) { self._bridged = bridged} +} /// Wraps the arguments specified in the specify_test instruction. public struct TestArguments { @@ -150,42 +138,27 @@ extension BridgedTestArguments { } /// Registration of each test in the SIL module. -public func registerOptimizerTests() { +public func registerTests() { // Register each test. - registerFunctionTests( + registerTests( + parseTestSpecificationTest, getAccessBaseTest, - addressOwnershipLiveRangeTest, - argumentConventionsTest, borrowIntroducersTest, enclosingValuesTest, forwardingDefUseTest, - forwardingUseDefTest, - getPullbackClosureInfoTest, - interiorLivenessTest, - lifetimeDependenceRootTest, - lifetimeDependenceScopeTest, - lifetimeDependenceUseTest, - linearLivenessTest, - localVariableReachableUsesTest, - localVariableReachingAssignmentsTest, - parseTestSpecificationTest, - rangeOverlapsPathTest, - rewrittenCallerBodyTest, - specializedFunctionSignatureAndBodyTest, - variableIntroducerTest + forwardingUseDefTest ) - // Finally register the thunk they all call through. - registerFunctionTestThunk(functionTestThunk) + registerTestThunk(testThunk) } -private func registerFunctionTests(_ tests: FunctionTest...) { - tests.forEach { registerFunctionTest($0) } +private func registerTests(_ tests: Test...) { + tests.forEach { registerTest($0) } } -private func registerFunctionTest(_ test: FunctionTest) { +private func registerTest(_ test: Test) { test.name._withBridgedStringRef { ref in - registerFunctionTest(ref, castToOpaquePointer(fromInvocation: test.invocation)) + registerTest(ref, castToOpaquePointer(fromInvocation: test.invocation)) } } @@ -193,17 +166,16 @@ private func registerFunctionTest(_ test: FunctionTest) { /// actual test function. /// /// This function is necessary because tests need to be written in terms of -/// native Swift types (Function, TestArguments, BridgedPassContext) +/// native Swift types (Function, TestArguments, TestContext) /// rather than their bridged variants, but such a function isn't representable -/// in C++. This thunk unwraps the bridged types and invokes the real -/// function. -private func functionTestThunk( +/// in C++. This thunk unwraps the bridged types and invokes the real function. +private func testThunk( _ erasedInvocation: UnsafeMutableRawPointer, - _ function: BridgedFunction, - _ arguments: BridgedTestArguments, - _ passInvocation: BridgedSwiftPassInvocation) { + _ function: BridgedFunction, + _ arguments: BridgedTestArguments, + _ bridgedContext: BridgedContext) { let invocation = castToInvocation(fromOpaquePointer: erasedInvocation) - let context = FunctionPassContext(_bridged: BridgedPassContext(invocation: passInvocation.invocation)) + let context = TestContext(bridged: bridgedContext) invocation(function.function, arguments.native, context) } @@ -211,16 +183,15 @@ private func functionTestThunk( /// /// Needed so that the closure can be represented in C++ for storage in the test /// registry. -private func castToOpaquePointer(fromInvocation invocation: FunctionTestInvocation) -> UnsafeMutableRawPointer { +private func castToOpaquePointer(fromInvocation invocation: TestInvocation) -> UnsafeMutableRawPointer { return unsafeBitCast(invocation, to: UnsafeMutableRawPointer.self) } /// Bitcast a void * to a thin test closure. /// -/// Needed so that the closure stored in the C++ test registry can be invoked -/// via the functionTestThunk. -private func castToInvocation(fromOpaquePointer erasedInvocation: UnsafeMutableRawPointer) -> FunctionTestInvocation { - return unsafeBitCast(erasedInvocation, to: FunctionTestInvocation.self) +/// Needed so that the closure stored in the C++ test registry can be invoked via the testThunk. +private func castToInvocation(fromOpaquePointer erasedInvocation: UnsafeMutableRawPointer) -> TestInvocation { + return unsafeBitCast(erasedInvocation, to: TestInvocation.self) } // Arguments: @@ -241,8 +212,7 @@ private func castToInvocation(fromOpaquePointer erasedInvocation: UnsafeMutableR // - for each argument (after the initial string) // - its type // - something to identify the instance (mostly this means calling dump) -let parseTestSpecificationTest = -FunctionTest("test_specification_parsing") { function, arguments, context in +let parseTestSpecificationTest = Test("test_specification_parsing") { function, arguments, context in let expectedFields = arguments.takeString() for expectedField in expectedFields.string { switch expectedField { diff --git a/SwiftCompilerSources/Sources/Optimizer/Utilities/Verifier.swift b/SwiftCompilerSources/Sources/SIL/Utilities/Verifier.swift similarity index 89% rename from SwiftCompilerSources/Sources/Optimizer/Utilities/Verifier.swift rename to SwiftCompilerSources/Sources/SIL/Utilities/Verifier.swift index 7bb7e42a6c0ed..e1e0c84d83b71 100644 --- a/SwiftCompilerSources/Sources/Optimizer/Utilities/Verifier.swift +++ b/SwiftCompilerSources/Sources/SIL/Utilities/Verifier.swift @@ -10,24 +10,29 @@ // //===----------------------------------------------------------------------===// -import SIL -import OptimizerBridging +import SILBridging +/// To add verification for a specific instruction, let the instruction class conform to +/// this protocol and implement the `verify` method. private protocol VerifiableInstruction : Instruction { - func verify(_ context: FunctionPassContext) + func verify(_ context: VerifierContext) } private func require(_ condition: Bool, _ message: @autoclosure () -> String, atInstruction: Instruction? = nil) { if !condition { let msg = message() msg._withBridgedStringRef { stringRef in - verifierError(stringRef, atInstruction.bridged, Optional.none.bridged) + BridgedVerifier.verifierError(stringRef, atInstruction.bridged, Optional.none.bridged) } } } +struct VerifierContext: Context { + let _bridged: BridgedContext +} + extension Function { - func verify(_ context: FunctionPassContext) { + func verify(_ context: VerifierContext) { for block in blocks { for arg in block.arguments { arg.verify(context) @@ -63,16 +68,17 @@ private extension Instruction { } private extension Argument { - func verify(_ context: FunctionPassContext) { + func verify(_ context: VerifierContext) { if let phi = Phi(self), phi.value.ownership == .guaranteed { phi.verifyBorrowedFromUse() - require(phi.isReborrow == phi.hasBorrowEndingUse || - // In a dead-end block an end_borrow might have been deleted. - // TODO: this check is not needed anymore once we have complete OSSA lifetimes. - (isReborrow && context.deadEndBlocks.isDeadEnd(parentBlock)), + // TODO: enable this check once we have complete OSSA lifetimes. + // In a dead-end block an end_borrow might have been deleted. + /* + require(phi.isReborrow == phi.hasBorrowEndingUse, "\(self) has stale reborrow flag"); + */ } } @@ -95,7 +101,7 @@ private extension Phi { } extension BorrowedFromInst : VerifiableInstruction { - func verify(_ context: FunctionPassContext) { + func verify(_ context: VerifierContext) { for ev in enclosingValues { require(ev.isValidEnclosingValueInBorrowedFrom, "invalid enclosing value in borrowed-from: \(ev)") @@ -135,7 +141,7 @@ private extension Value { } extension LoadBorrowInst : VerifiableInstruction { - func verify(_ context: FunctionPassContext) { + func verify(_ context: VerifierContext) { if isUnchecked { return } @@ -149,7 +155,7 @@ extension LoadBorrowInst : VerifiableInstruction { } extension VectorBaseAddrInst : VerifiableInstruction { - func verify(_ context: FunctionPassContext) { + func verify(_ context: VerifierContext) { require(vector.type.isBuiltinFixedArray, "vector operand of vector_element_addr must be a Builtin.FixedArray") require(type == vector.type.builtinFixedArrayElementType(in: parentFunction, @@ -164,10 +170,10 @@ extension VectorBaseAddrInst : VerifiableInstruction { // Otherwise the risk would be too big for false alarms. It also means that this verification is not perfect and // might miss some subtle violations. private struct MutatingUsesWalker : AddressDefUseWalker { - let context: FunctionPassContext + let context: VerifierContext var mutatingInstructions: InstructionSet - init(_ context: FunctionPassContext) { + init(_ context: VerifierContext) { self.context = context self.mutatingInstructions = InstructionSet(context) } @@ -268,9 +274,9 @@ private extension Operand { } func registerVerifier() { - BridgedUtilities.registerVerifier( - { (bridgedCtxt: BridgedPassContext, bridgedFunction: BridgedFunction) in - let context = FunctionPassContext(_bridged: bridgedCtxt) + BridgedVerifier.registerVerifier( + { (bridgedCtxt: BridgedContext, bridgedFunction: BridgedFunction) in + let context = VerifierContext(_bridged: bridgedCtxt) bridgedFunction.function.verify(context) } ) diff --git a/SwiftCompilerSources/Sources/SIL/Value.swift b/SwiftCompilerSources/Sources/SIL/Value.swift index c0397df172d59..a346cb621ba80 100644 --- a/SwiftCompilerSources/Sources/SIL/Value.swift +++ b/SwiftCompilerSources/Sources/SIL/Value.swift @@ -298,6 +298,10 @@ public final class Undef : Value { public var hasTrivialNonPointerType: Bool { false } public var isLexical: Bool { false } + + public static func get(type: Type, _ context: some MutatingContext) -> Undef { + context._bridged.getSILUndef(type.bridged).value as! Undef + } } final class PlaceholderValue : Value { diff --git a/include/swift/SIL/SILBridging.h b/include/swift/SIL/SILBridging.h index 5e99a8d88edea..1fb3c2b1dc65f 100644 --- a/include/swift/SIL/SILBridging.h +++ b/include/swift/SIL/SILBridging.h @@ -36,8 +36,10 @@ struct BridgedBasicBlock; struct BridgedSuccessorArray; struct OptionalBridgedBasicBlock; struct BridgedDeclRef; +struct BridgedContext; namespace swift { +class SILContext; class ValueBase; class Operand; struct SILDebugVariable; @@ -61,7 +63,6 @@ class SILDefaultWitnessTable; class SILDebugLocation; class NominalTypeDecl; class VarDecl; -class SwiftPassInvocation; class GenericSpecializationInformation; class LifetimeDependenceInfo; class IndexSubset; @@ -71,6 +72,12 @@ class SILParameterInfo; struct SILDeclRef; class SILBuilder; class SILLocation; +class BasicBlockSet; +class NodeSet; +class OperandSet; +class ClonerWithFixedLocation; +class FixedSizeSlabPayload; +class FixedSizeSlab; } bool swiftModulesInitialized(); @@ -1331,24 +1338,179 @@ struct BridgedBuilder{ SWIFT_IMPORT_UNSAFE void destroyCapturedArgs(BridgedInstruction partialApply) const; }; -// Passmanager and Context +// Context -namespace swift { - class SwiftPassInvocation; -} +struct BridgedBasicBlockSet { + swift::BasicBlockSet * _Nonnull set; -struct BridgedChangeNotificationHandler { - swift::SwiftPassInvocation * _Nonnull invocation; + BRIDGED_INLINE bool contains(BridgedBasicBlock block) const; + BRIDGED_INLINE bool insert(BridgedBasicBlock block) const; + BRIDGED_INLINE void erase(BridgedBasicBlock block) const; + SWIFT_IMPORT_UNSAFE BRIDGED_INLINE BridgedFunction getFunction() const; +}; - enum class Kind { - instructionsChanged, - callsChanged, - branchesChanged, - effectsChanged, - functionTablesChanged +struct BridgedNodeSet { + swift::NodeSet * _Nonnull set; + + BRIDGED_INLINE bool containsValue(BridgedValue value) const; + BRIDGED_INLINE bool insertValue(BridgedValue value) const; + BRIDGED_INLINE void eraseValue(BridgedValue value) const; + BRIDGED_INLINE bool containsInstruction(BridgedInstruction inst) const; + BRIDGED_INLINE bool insertInstruction(BridgedInstruction inst) const; + BRIDGED_INLINE void eraseInstruction(BridgedInstruction inst) const; + SWIFT_IMPORT_UNSAFE BRIDGED_INLINE BridgedFunction getFunction() const; +}; + +struct BridgedOperandSet { + swift::OperandSet * _Nonnull set; + + BRIDGED_INLINE bool contains(BridgedOperand operand) const; + BRIDGED_INLINE bool insert(BridgedOperand operand) const; + BRIDGED_INLINE void erase(BridgedOperand operand) 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 { + swift::SILContext * _Nonnull context; + + enum class SILStage { + Raw, + Canonical, + Lowered }; - void notifyChanges(Kind changeKind) const; + enum class NotificationKind { + Instructions = 0x1, + Calls = 0x2, + Branches = 0x4, + Effects = 0x8, + FunctionTables = 0x10 + }; + + BRIDGED_INLINE bool isTransforming(BridgedFunction function) const; + BRIDGED_INLINE void notifyChanges(NotificationKind changeKind) const; + + // Module + + BridgedOwnedString getModuleDescription() const; + BRIDGED_INLINE SILStage getSILStage() const; + BRIDGED_INLINE bool moduleIsSerialized() const; + BRIDGED_INLINE bool moduleHasLoweredAddresses() const; + SWIFT_IMPORT_UNSAFE BRIDGED_INLINE BridgedDeclObj getCurrentModuleContext() const; + SWIFT_IMPORT_UNSAFE BRIDGED_INLINE OptionalBridgedFunction lookupFunction(BridgedStringRef name) const; + SWIFT_IMPORT_UNSAFE BRIDGED_INLINE OptionalBridgedVTable lookupVTable(BridgedDeclObj classDecl) const; + SWIFT_IMPORT_UNSAFE BRIDGED_INLINE OptionalBridgedVTable lookupSpecializedVTable(BridgedType classType) const; + SWIFT_IMPORT_UNSAFE BRIDGED_INLINE void loadFunction(BridgedFunction function, bool loadCalleesRecursively) const; + SWIFT_IMPORT_UNSAFE BRIDGED_INLINE OptionalBridgedFunction loadFunction(BridgedStringRef name, + bool loadCalleesRecursively) const; + SWIFT_IMPORT_UNSAFE BRIDGED_INLINE OptionalBridgedFunction lookupStdlibFunction(BridgedStringRef name) const; + SWIFT_IMPORT_UNSAFE OptionalBridgedFunction lookUpNominalDeinitFunction(BridgedDeclObj nominal) const; + SWIFT_IMPORT_UNSAFE BRIDGED_INLINE BridgedSubstitutionMap getContextSubstitutionMap(BridgedType type) const; + SWIFT_IMPORT_UNSAFE BRIDGED_INLINE BridgedType getBuiltinIntegerType(SwiftInt bitWidth) const; + SWIFT_IMPORT_UNSAFE BRIDGED_INLINE BridgedDeclObj getSwiftArrayDecl() const; + SWIFT_IMPORT_UNSAFE BRIDGED_INLINE BridgedDeclObj getSwiftMutableSpanDecl() const; + SWIFT_IMPORT_UNSAFE BRIDGED_INLINE BridgedValue getSILUndef(BridgedType type) const; + SWIFT_IMPORT_UNSAFE BRIDGED_INLINE + BridgedConformance getSpecializedConformance(BridgedConformance genericConformance, + BridgedASTType type, + BridgedSubstitutionMap substitutions) const; + SWIFT_IMPORT_UNSAFE BRIDGED_INLINE + OptionalBridgedWitnessTable lookupWitnessTable(BridgedConformance conformance) const; + BRIDGED_INLINE bool calleesAreStaticallyKnowable(BridgedDeclRef method) const; + + + // Modifying the Module + + SWIFT_IMPORT_UNSAFE BRIDGED_INLINE BridgedWitnessTable createSpecializedWitnessTable(BridgedLinkage linkage, + bool serialized, + BridgedConformance conformance, + BridgedArrayRef bridgedEntries) const; + SWIFT_IMPORT_UNSAFE BRIDGED_INLINE BridgedVTable createSpecializedVTable(BridgedType classType, + bool serialized, + BridgedArrayRef bridgedEntries) const; + SWIFT_IMPORT_UNSAFE BridgedFunction createEmptyFunction(BridgedStringRef name, + const BridgedParameterInfo * _Nullable bridgedParams, + SwiftInt paramCount, + bool hasSelfParam, + BridgedFunction fromFunc) const; + SWIFT_IMPORT_UNSAFE BridgedGlobalVar createGlobalVariable(BridgedStringRef name, BridgedType type, + BridgedLinkage linkage, bool isLet) const; + void moveFunctionBody(BridgedFunction sourceFunc, BridgedFunction destFunc) const; + + // Function-local SIL modifications + + SWIFT_IMPORT_UNSAFE BRIDGED_INLINE BridgedBasicBlock splitBlockBefore(BridgedInstruction bridgedInst) const; + SWIFT_IMPORT_UNSAFE BRIDGED_INLINE BridgedBasicBlock splitBlockAfter(BridgedInstruction bridgedInst) const; + SWIFT_IMPORT_UNSAFE BRIDGED_INLINE BridgedBasicBlock createBlockAfter(BridgedBasicBlock bridgedBlock) const; + SWIFT_IMPORT_UNSAFE BRIDGED_INLINE BridgedBasicBlock appendBlock(BridgedFunction bridgedFunction) const; + BRIDGED_INLINE void eraseInstruction(BridgedInstruction inst, bool salvageDebugInfo) const; + BRIDGED_INLINE void eraseBlock(BridgedBasicBlock block) const; + static BRIDGED_INLINE void moveInstructionBefore(BridgedInstruction inst, BridgedInstruction beforeInst); + + // SSAUpdater + + BRIDGED_INLINE void SSAUpdater_initialize(BridgedFunction function, BridgedType type, + BridgedValue::Ownership ownership) const; + BRIDGED_INLINE void SSAUpdater_addAvailableValue(BridgedBasicBlock block, BridgedValue value) const; + SWIFT_IMPORT_UNSAFE BRIDGED_INLINE BridgedValue SSAUpdater_getValueAtEndOfBlock(BridgedBasicBlock block) const; + SWIFT_IMPORT_UNSAFE BRIDGED_INLINE BridgedValue SSAUpdater_getValueInMiddleOfBlock(BridgedBasicBlock block) const; + BRIDGED_INLINE SwiftInt SSAUpdater_getNumInsertedPhis() const; + SWIFT_IMPORT_UNSAFE BRIDGED_INLINE BridgedValue SSAUpdater_getInsertedPhi(SwiftInt idx) const; + + // Sets + + SWIFT_IMPORT_UNSAFE BRIDGED_INLINE BridgedBasicBlockSet allocBasicBlockSet() const; + BRIDGED_INLINE void freeBasicBlockSet(BridgedBasicBlockSet set) const; + SWIFT_IMPORT_UNSAFE BRIDGED_INLINE BridgedNodeSet allocNodeSet() const; + BRIDGED_INLINE void freeNodeSet(BridgedNodeSet set) const; + SWIFT_IMPORT_UNSAFE BRIDGED_INLINE BridgedOperandSet allocOperandSet() const; + BRIDGED_INLINE void freeOperandSet(BridgedOperandSet set) const; + + // Slabs + + struct Slab { + swift::FixedSizeSlabPayload * _Nullable data = nullptr; + + BRIDGED_INLINE static SwiftInt getCapacity(); + BRIDGED_INLINE Slab(swift::FixedSizeSlab * _Nullable slab); + BRIDGED_INLINE swift::FixedSizeSlab * _Nullable getSlab() const; + SWIFT_IMPORT_UNSAFE BRIDGED_INLINE Slab getNext() const; + SWIFT_IMPORT_UNSAFE BRIDGED_INLINE Slab getPrevious() const; + }; + + SWIFT_IMPORT_UNSAFE BRIDGED_INLINE Slab allocSlab(Slab afterSlab) const; + SWIFT_IMPORT_UNSAFE BRIDGED_INLINE Slab freeSlab(Slab slab) const; +}; + +struct BridgedVerifier { + typedef void (* _Nonnull VerifyFunctionFn)(BridgedContext, BridgedFunction); + + static void runSwiftFunctionVerification(swift::SILFunction * _Nonnull f, swift::SILContext * _Nonnull context); + + static void registerVerifier(VerifyFunctionFn verifyFunctionFn); + static void verifierError(BridgedStringRef message, OptionalBridgedInstruction atInstruction, + OptionalBridgedArgument atArgument); +}; + +struct BridgedUtilities { + typedef void (* _Nonnull UpdateFunctionFn)(BridgedContext, BridgedFunction); + typedef void (* _Nonnull UpdatePhisFn)(BridgedContext, BridgedArrayRef); + + static void registerPhiUpdater(UpdateFunctionFn updateBorrowedFromFn, + UpdatePhisFn updateBorrowedFromPhisFn, + UpdatePhisFn replacePhisWithIncomingValuesFn); }; namespace swift::test { @@ -1375,18 +1537,11 @@ struct BridgedTestArguments { SWIFT_IMPORT_UNSAFE BridgedFunction takeFunction() const; }; -struct BridgedSwiftPassInvocation { - swift::SwiftPassInvocation *_Nonnull invocation; -}; - using SwiftNativeFunctionTestThunk = - void (*_Nonnull)(void *_Nonnull, BridgedFunction, BridgedTestArguments, - BridgedSwiftPassInvocation); - -void registerFunctionTestThunk(SwiftNativeFunctionTestThunk); + void (*_Nonnull)(void *_Nonnull, BridgedFunction, BridgedTestArguments, BridgedContext); -void registerFunctionTest(BridgedStringRef, - void *_Nonnull nativeSwiftInvocation); +void registerTestThunk(SwiftNativeFunctionTestThunk); +void registerTest(BridgedStringRef, void *_Nonnull nativeSwiftContext); SWIFT_END_NULLABILITY_ANNOTATIONS diff --git a/include/swift/SIL/SILBridgingImpl.h b/include/swift/SIL/SILBridgingImpl.h index 84fd07e0a53bc..6f68edad1a590 100644 --- a/include/swift/SIL/SILBridgingImpl.h +++ b/include/swift/SIL/SILBridgingImpl.h @@ -28,8 +28,10 @@ #include "swift/AST/Types.h" #include "swift/Basic/BasicBridging.h" #include "swift/SIL/ApplySite.h" +#include "swift/SIL/CalleeCache.h" #include "swift/SIL/DynamicCasts.h" #include "swift/SIL/InstWrappers.h" +#include "swift/SIL/SILContext.h" #include "swift/SIL/SILBuilder.h" #include "swift/SIL/SILDefaultWitnessTable.h" #include "swift/SIL/SILFunctionConventions.h" @@ -2673,6 +2675,334 @@ BridgedInstruction BridgedBuilder::createConvertEscapeToNoEscape(BridgedValue or return {unbridged().createConvertEscapeToNoEscape(regularLoc(), originalFunction.getSILValue(), resultType.unbridged(), isLifetimeGuaranteed)}; } +//===----------------------------------------------------------------------===// +// BridgedBasicBlockSet +//===----------------------------------------------------------------------===// + +bool BridgedBasicBlockSet::contains(BridgedBasicBlock block) const { + return set->contains(block.unbridged()); +} + +bool BridgedBasicBlockSet::insert(BridgedBasicBlock block) const { + return set->insert(block.unbridged()); +} + +void BridgedBasicBlockSet::erase(BridgedBasicBlock block) const { + set->erase(block.unbridged()); +} + +BridgedFunction BridgedBasicBlockSet::getFunction() const { + return {set->getFunction()}; +} + +//===----------------------------------------------------------------------===// +// BridgedNodeSet +//===----------------------------------------------------------------------===// + +bool BridgedNodeSet::containsValue(BridgedValue value) const { + return set->contains(value.getSILValue()); +} + +bool BridgedNodeSet::insertValue(BridgedValue value) const { + return set->insert(value.getSILValue()); +} + +void BridgedNodeSet::eraseValue(BridgedValue value) const { + set->erase(value.getSILValue()); +} + +bool BridgedNodeSet::containsInstruction(BridgedInstruction inst) const { + return set->contains(inst.unbridged()->asSILNode()); +} + +bool BridgedNodeSet::insertInstruction(BridgedInstruction inst) const { + return set->insert(inst.unbridged()->asSILNode()); +} + +void BridgedNodeSet::eraseInstruction(BridgedInstruction inst) const { + set->erase(inst.unbridged()->asSILNode()); +} + +BridgedFunction BridgedNodeSet::getFunction() const { + return {set->getFunction()}; +} + +//===----------------------------------------------------------------------===// +// BridgedOperandSet +//===----------------------------------------------------------------------===// + +bool BridgedOperandSet::contains(BridgedOperand operand) const { + return set->contains(operand.op); +} + +bool BridgedOperandSet::insert(BridgedOperand operand) const { + return set->insert(operand.op); +} + +void BridgedOperandSet::erase(BridgedOperand operand) const { + set->erase(operand.op); +} + +BridgedFunction BridgedOperandSet::getFunction() const { + return {set->getFunction()}; +} + +//===----------------------------------------------------------------------===// +// BridgedContext +//===----------------------------------------------------------------------===// + +static_assert((int)BridgedContext::NotificationKind::Instructions == + (int)swift::SILContext::NotificationKind::Instructions); +static_assert((int)BridgedContext::NotificationKind::Calls == + (int)swift::SILContext::NotificationKind::Calls); +static_assert((int)BridgedContext::NotificationKind::Branches == + (int)swift::SILContext::NotificationKind::Branches); +static_assert((int)BridgedContext::NotificationKind::Effects == + (int)swift::SILContext::NotificationKind::Effects); +static_assert((int)BridgedContext::NotificationKind::FunctionTables == + (int)swift::SILContext::NotificationKind::FunctionTables); + +static_assert((int)BridgedContext::SILStage::Raw == (int)swift::SILStage::Raw); +static_assert((int)BridgedContext::SILStage::Canonical == (int)swift::SILStage::Canonical); +static_assert((int)BridgedContext::SILStage::Lowered == (int)swift::SILStage::Lowered); + +bool BridgedContext::isTransforming(BridgedFunction function) const { + return context->getFunction() == function.getFunction(); +} + +void BridgedContext::notifyChanges(NotificationKind changeKind) const { + context->notifyChanges((swift::SILContext::NotificationKind)changeKind); +} + +BridgedContext::SILStage BridgedContext::getSILStage() const { + return (SILStage)context->getModule()->getStage(); +} + +bool BridgedContext::moduleIsSerialized() const { + return context->getModule()->isSerialized(); +} + +bool BridgedContext::moduleHasLoweredAddresses() const { + return context->getModule()->useLoweredAddresses(); +} + +BridgedDeclObj BridgedContext::getCurrentModuleContext() const { + return {context->getModule()->getSwiftModule()}; +} + +OptionalBridgedFunction BridgedContext::lookupFunction(BridgedStringRef name) const { + return {context->getModule()->lookUpFunction(name.unbridged())}; +} + +OptionalBridgedVTable BridgedContext::lookupVTable(BridgedDeclObj classDecl) const { + return {context->getModule()->lookUpVTable(classDecl.getAs())}; +} + +OptionalBridgedVTable BridgedContext::lookupSpecializedVTable(BridgedType classType) const { + return {context->getModule()->lookUpSpecializedVTable(classType.unbridged())}; +} + +OptionalBridgedFunction BridgedContext::loadFunction(BridgedStringRef name, bool loadCalleesRecursively) const { + return {context->getModule()->loadFunction(name.unbridged(), + loadCalleesRecursively + ? swift::SILModule::LinkingMode::LinkAll + : swift::SILModule::LinkingMode::LinkNormal)}; +} + +void BridgedContext::loadFunction(BridgedFunction function, bool loadCalleesRecursively) const { + context->getModule()->loadFunction(function.getFunction(), + loadCalleesRecursively ? swift::SILModule::LinkingMode::LinkAll + : swift::SILModule::LinkingMode::LinkNormal); +} + +BridgedSubstitutionMap BridgedContext::getContextSubstitutionMap(BridgedType type) const { + swift::SILType ty = type.unbridged(); + return ty.getASTType()->getContextSubstitutionMap(); +} + +BridgedType BridgedContext::getBuiltinIntegerType(SwiftInt bitWidth) const { + return swift::SILType::getBuiltinIntegerType(bitWidth, context->getModule()->getASTContext()); +} + +BridgedDeclObj BridgedContext::getSwiftArrayDecl() const { + return {context->getModule()->getASTContext().getArrayDecl()}; +} + +BridgedDeclObj BridgedContext::getSwiftMutableSpanDecl() const { + return {context->getModule()->getASTContext().getMutableSpanDecl()}; +} + +BridgedValue BridgedContext::getSILUndef(BridgedType type) const { + return {swift::SILUndef::get(context->getFunction(), type.unbridged())}; +} + +BridgedConformance BridgedContext::getSpecializedConformance( + BridgedConformance genericConformance, + BridgedASTType type, + BridgedSubstitutionMap substitutions) const { + auto &ctxt = context->getModule()->getASTContext(); + auto *genConf = llvm::cast(genericConformance.unbridged().getConcrete()); + auto *c = ctxt.getSpecializedConformance(type.unbridged(), genConf, substitutions.unbridged()); + return swift::ProtocolConformanceRef(c); +} + +OptionalBridgedWitnessTable BridgedContext::lookupWitnessTable(BridgedConformance conformance) const { + swift::ProtocolConformanceRef ref = conformance.unbridged(); + if (!ref.isConcrete()) { + return {nullptr}; + } + return {context->getModule()->lookUpWitnessTable(ref.getConcrete())}; +} + +bool BridgedContext::calleesAreStaticallyKnowable(BridgedDeclRef method) const { + return swift::calleesAreStaticallyKnowable(*context->getModule(), method.unbridged()); +} + +BridgedWitnessTable BridgedContext::createSpecializedWitnessTable(BridgedLinkage linkage, + bool serialized, + BridgedConformance conformance, + BridgedArrayRef bridgedEntries) const { + llvm::SmallVector entries; + for (const BridgedWitnessTableEntry &e : bridgedEntries.unbridged()) { + entries.push_back(e.unbridged()); + } + return {swift::SILWitnessTable::create(*context->getModule(), (swift::SILLinkage)linkage, + serialized ? swift::IsSerialized : swift::IsNotSerialized, + conformance.unbridged().getConcrete(), + entries, {}, /*specialized=*/true)}; +} + +BridgedVTable BridgedContext::createSpecializedVTable(BridgedType classType, + bool serialized, + BridgedArrayRef bridgedEntries) const { + llvm::SmallVector entries; + for (const BridgedVTableEntry &e : bridgedEntries.unbridged()) { + entries.push_back(e.unbridged()); + } + swift::SILType classTy = classType.unbridged(); + return {swift::SILVTable::create(*context->getModule(), + classTy.getClassOrBoundGenericClass(), classTy, + serialized ? swift::IsSerialized : swift::IsNotSerialized, + entries)}; +} + +BridgedBasicBlock BridgedContext::splitBlockBefore(BridgedInstruction bridgedInst) const { + auto *block = bridgedInst.unbridged()->getParent(); + return {block->split(bridgedInst.unbridged()->getIterator())}; +} + +BridgedBasicBlock BridgedContext::splitBlockAfter(BridgedInstruction bridgedInst) const { + auto *block = bridgedInst.unbridged()->getParent(); + return {block->split(std::next(bridgedInst.unbridged()->getIterator()))}; +} + +BridgedBasicBlock BridgedContext::createBlockAfter(BridgedBasicBlock bridgedBlock) const { + swift::SILBasicBlock *block = bridgedBlock.unbridged(); + return {block->getParent()->createBasicBlockAfter(block)}; +} + +BridgedBasicBlock BridgedContext::appendBlock(BridgedFunction bridgedFunction) const { + return {bridgedFunction.getFunction()->createBasicBlock()}; +} + +void BridgedContext::eraseInstruction(BridgedInstruction inst, bool salvageDebugInfo) const { + context->eraseInstruction(inst.unbridged(), salvageDebugInfo); +} + +void BridgedContext::eraseBlock(BridgedBasicBlock block) const { + block.unbridged()->eraseFromParent(); +} + +void BridgedContext::moveInstructionBefore(BridgedInstruction inst, BridgedInstruction beforeInst) { + swift::SILBasicBlock::moveInstruction(inst.unbridged(), beforeInst.unbridged()); +} + +OptionalBridgedFunction BridgedContext::lookupStdlibFunction(BridgedStringRef name) const { + return {context->lookupStdlibFunction(name.unbridged())}; +} + +void BridgedContext::SSAUpdater_initialize(BridgedFunction function, BridgedType type, + BridgedValue::Ownership ownership) const { + context->initializeSSAUpdater(function.getFunction(), type.unbridged(), BridgedValue::unbridge(ownership)); +} + +void BridgedContext::SSAUpdater_addAvailableValue(BridgedBasicBlock block, BridgedValue value) const { + context->SSAUpdater_addAvailableValue(block.unbridged(), value.getSILValue()); +} + +BridgedValue BridgedContext::SSAUpdater_getValueAtEndOfBlock(BridgedBasicBlock block) const { + return {context->SSAUpdater_getValueAtEndOfBlock(block.unbridged())}; +} + +BridgedValue BridgedContext::SSAUpdater_getValueInMiddleOfBlock(BridgedBasicBlock block) const { + return {context->SSAUpdater_getValueInMiddleOfBlock(block.unbridged())}; +} + +SwiftInt BridgedContext::SSAUpdater_getNumInsertedPhis() const { + return (SwiftInt)context->SSAUpdater_getInsertedPhis().size(); +} + +BridgedValue BridgedContext::SSAUpdater_getInsertedPhi(SwiftInt idx) const { + return {context->SSAUpdater_getInsertedPhis()[idx]}; +} + +BridgedBasicBlockSet BridgedContext::allocBasicBlockSet() const { + return {context->allocBlockSet()}; +} + +void BridgedContext::freeBasicBlockSet(BridgedBasicBlockSet set) const { + context->freeBlockSet(set.set); +} + +BridgedNodeSet BridgedContext::allocNodeSet() const { + return {context->allocNodeSet()}; +} + +void BridgedContext::freeNodeSet(BridgedNodeSet set) const { + context->freeNodeSet(set.set); +} + +BridgedOperandSet BridgedContext::allocOperandSet() const { + return {context->allocOperandSet()}; +} + +void BridgedContext::freeOperandSet(BridgedOperandSet set) const { + context->freeOperandSet(set.set); +} + +SwiftInt BridgedContext::Slab::getCapacity() { + return (SwiftInt)swift::FixedSizeSlabPayload::capacity; +} + +BridgedContext::Slab::Slab(swift::FixedSizeSlab * _Nullable slab) { + if (slab) { + data = slab; + assert((void *)data == slab->dataFor()); + } +} + +swift::FixedSizeSlab * _Nullable BridgedContext::Slab::getSlab() const { + if (data) + return static_cast(data); + return nullptr; +} + +BridgedContext::Slab BridgedContext::Slab::getNext() const { + return &*std::next(getSlab()->getIterator()); +} + +BridgedContext::Slab BridgedContext::Slab::getPrevious() const { + return &*std::prev(getSlab()->getIterator()); +} + +BridgedContext::Slab BridgedContext::allocSlab(Slab afterSlab) const { + return context->allocSlab(afterSlab.getSlab()); +} + +BridgedContext::Slab BridgedContext::freeSlab(Slab slab) const { + return context->freeSlab(slab.getSlab()); +} + SWIFT_END_NULLABILITY_ANNOTATIONS #endif diff --git a/include/swift/SIL/SILContext.h b/include/swift/SIL/SILContext.h new file mode 100644 index 0000000000000..957fa72e7eee0 --- /dev/null +++ b/include/swift/SIL/SILContext.h @@ -0,0 +1,130 @@ +//===--- SILContext.h -------------------------------------------*- C++ -*-===// +// +// This source file is part of the Swift.org open source project +// +// Copyright (c) 2014 - 2025 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 +// +//===----------------------------------------------------------------------===// + +#ifndef SWIFT_SIL_SILBRIDGINGCONTEXT_H +#define SWIFT_SIL_SILBRIDGINGCONTEXT_H + +#include "swift/SIL/SILFunction.h" +#include "swift/SIL/BasicBlockBits.h" +#include "swift/SIL/NodeBits.h" +#include "swift/SIL/OperandBits.h" + +namespace swift { + +class SILSSAUpdater; + +/// The abstract base class for the C++ implementation of Context in SwiftCompilerSources. +/// Referenced in BridgedContext. +/// +/// Everything which only needs SIL is directly implemented in this class. +/// Everything which needs the SILPassManager is implemented in the derived class SwiftPassInvocation. +/// +class SILContext { +public: + enum NotificationKind : unsigned { + Nothing = 0, + Instructions = 0x1, + Calls = 0x2, + Branches = 0x4, + Effects = 0x8, + FunctionTables = 0x10 + }; + +protected: + SILContext(SILFunction *f) : function(f), mod(&f->getModule()) {} + SILContext(SILModule *mod) : mod(mod) {} + + virtual ~SILContext(); + + /// The currently optimized function or null if this is the context of a module pass. + SILFunction *function = nullptr; + + SILModule *mod = nullptr; + + /// All slabs, allocated by the pass. + SILModule::SlabList allocatedSlabs; + + static constexpr int BlockSetCapacity = SILBasicBlock::numCustomBits; + char blockSetStorage[sizeof(BasicBlockSet) * BlockSetCapacity]; + bool aliveBlockSets[BlockSetCapacity]; + int numBlockSetsAllocated = 0; + + static constexpr int NodeSetCapacity = SILNode::numCustomBits; + char nodeSetStorage[sizeof(NodeSet) * NodeSetCapacity]; + bool aliveNodeSets[NodeSetCapacity]; + int numNodeSetsAllocated = 0; + + static constexpr int OperandSetCapacity = Operand::numCustomBits; + char operandSetStorage[sizeof(OperandSet) * OperandSetCapacity]; + bool aliveOperandSets[OperandSetCapacity]; + int numOperandSetsAllocated = 0; + + int numClonersAllocated = 0; + + SILSSAUpdater *ssaUpdater = nullptr; + SmallVector insertedPhisBySSAUpdater; + + /// Change notifications, collected during a pass run. + NotificationKind changeNotifications = NotificationKind::Nothing; + + void verifyEverythingIsCleared(); + +public: + SILModule *getModule() const { return mod; } + SILFunction *getFunction() const { + ASSERT(function != nullptr && "not in a function pass"); + return function; + } + + /// Called by the pass when changes are made to the SIL. + void notifyChanges(NotificationKind notification) { + changeNotifications = (NotificationKind)(changeNotifications | notification); + } + + FixedSizeSlab *allocSlab(FixedSizeSlab *afterSlab); + + FixedSizeSlab *freeSlab(FixedSizeSlab *slab); + + BasicBlockSet *allocBlockSet(); + + void freeBlockSet(BasicBlockSet *set); + + NodeSet *allocNodeSet(); + + void freeNodeSet(NodeSet *set); + + OperandSet *allocOperandSet(); + + void freeOperandSet(OperandSet *set); + + void notifyNewCloner() { numClonersAllocated++; } + void notifyClonerDestroyed() { numClonersAllocated--; } + + virtual void eraseInstruction(SILInstruction *inst, bool salvageDebugInfo) = 0; + virtual SILFunction *createEmptyFunction(StringRef name, ArrayRef params, + bool hasSelfParam, SILFunction *fromFn) = 0; + virtual void moveFunctionBody(SILFunction *sourceFn, SILFunction *destFn) = 0; + + virtual SILFunction *lookupStdlibFunction(StringRef name) = 0; + + // The SILSSAUpdater is implemented in the Optimizer. Therefore all the APIs need to take + // the indirection through virtual functions to SwiftPassInvocation. + virtual void initializeSSAUpdater(SILFunction *function, SILType type, ValueOwnershipKind ownership) = 0; + virtual void SSAUpdater_addAvailableValue(SILBasicBlock *block, SILValue value) = 0; + virtual SILValue SSAUpdater_getValueAtEndOfBlock(SILBasicBlock *block) = 0; + virtual SILValue SSAUpdater_getValueInMiddleOfBlock(SILBasicBlock *block) = 0; + ArrayRef SSAUpdater_getInsertedPhis() { return insertedPhisBySSAUpdater; } +}; + +} // namespace swift + +#endif diff --git a/include/swift/SIL/Test.h b/include/swift/SIL/Test.h index 7acac7d5f862e..47124ffd57fd6 100644 --- a/include/swift/SIL/Test.h +++ b/include/swift/SIL/Test.h @@ -141,6 +141,8 @@ class FunctionTest final { /// The lambda to be run. TaggedUnion invocation; + bool isSwiftSILTest = false; + public: /// Creates a test that will run \p invocation and stores it in the global /// registry. @@ -158,7 +160,8 @@ class FunctionTest final { /// Creates a test that will run \p invocation and stores it in the global /// registry. static void createNativeSwiftFunctionTest(StringRef name, - NativeSwiftInvocation invocation); + NativeSwiftInvocation invocation, + bool isSILTest); /// Computes and returns the function's dominance tree. DominanceInfo *getDominanceInfo(); @@ -179,7 +182,7 @@ class FunctionTest final { SILFunctionTransform *getPass(); - SwiftPassInvocation *getSwiftPassInvocation(); + SILContext *getSILContext(); //===----------------------------------------------------------------------===// //=== MARK: Implementation Details === @@ -260,7 +263,7 @@ class FunctionTest final { virtual DominanceInfo *getDominanceInfo() = 0; virtual DeadEndBlocks *getDeadEndBlocks() = 0; virtual SILPassManager *getPassManager() = 0; - virtual SwiftPassInvocation *getSwiftPassInvocation() = 0; + virtual SILContext *getSILContext() = 0; virtual ~Dependencies(){}; }; @@ -271,7 +274,7 @@ class FunctionTest final { public: /// Creates a test that will run \p invocation. For use by /// createNativeSwiftFunctionTest. - FunctionTest(StringRef name, NativeSwiftInvocation invocation); + FunctionTest(StringRef name, NativeSwiftInvocation invocation, bool isSILTest); }; /// Thunks for delaying template instantiation. diff --git a/include/swift/SILOptimizer/Analysis/Analysis.h b/include/swift/SILOptimizer/Analysis/Analysis.h index a0647818b0418..3a3afbd75b8db 100644 --- a/include/swift/SILOptimizer/Analysis/Analysis.h +++ b/include/swift/SILOptimizer/Analysis/Analysis.h @@ -15,6 +15,8 @@ #include "swift/Basic/NullablePtr.h" #include "swift/SIL/Notifications.h" +#include "swift/SIL/SILModule.h" +#include "swift/SIL/SILContext.h" #include "llvm/ADT/DenseMap.h" #include "llvm/Support/Casting.h" @@ -49,25 +51,25 @@ class SILAnalysis { /// The pass created, deleted or rearranged some instructions in a /// function. - Instructions = 0x1, + Instructions = SILContext::NotificationKind::Instructions, /// The pass modified some calls (apply instructions). /// /// The intention of this invalidation kind is to allow analysis that /// rely on a specific call graph structure to recompute themselves. - Calls = 0x2, + Calls = SILContext::NotificationKind::Calls, /// A pass has invalidated some branches in the program. /// /// The intention of this invalidation kind is to tell analyses like the /// Dominance Analysis and the PostOrder Analysis that the underlying CFG /// has been modified. - Branches = 0x4, + Branches = SILContext::NotificationKind::Branches, /// The function effects. /// /// The computed effects of the function are invalidated. - Effects = 0x8, + Effects = SILContext::NotificationKind::Effects, /// Convenience states: FunctionBody = Calls | Branches | Instructions, diff --git a/include/swift/SILOptimizer/OptimizerBridging.h b/include/swift/SILOptimizer/OptimizerBridging.h index a12bf806cc834..efab99a89aef6 100644 --- a/include/swift/SILOptimizer/OptimizerBridging.h +++ b/include/swift/SILOptimizer/OptimizerBridging.h @@ -42,13 +42,7 @@ class CalleeList; class DeadEndBlocks; class DominanceInfo; class PostDominanceInfo; -class BasicBlockSet; -class NodeSet; -class OperandSet; -class ClonerWithFixedLocation; class SwiftPassInvocation; -class FixedSizeSlabPayload; -class FixedSizeSlab; class SILVTable; class SpecializationCloner; } @@ -65,14 +59,14 @@ struct BridgedAliasAnalysis { typedef void (* _Nonnull InitFn)(BridgedAliasAnalysis aliasAnalysis, SwiftInt size); typedef void (* _Nonnull DestroyFn)(BridgedAliasAnalysis aliasAnalysis); typedef BridgedMemoryBehavior (* _Nonnull GetMemEffectFn)( - BridgedPassContext context, BridgedAliasAnalysis aliasAnalysis, + BridgedContext context, BridgedAliasAnalysis aliasAnalysis, BridgedValue, BridgedInstruction); typedef bool (* _Nonnull Escaping2InstFn)( - BridgedPassContext context, BridgedAliasAnalysis aliasAnalysis, BridgedValue, BridgedInstruction); + BridgedContext context, BridgedAliasAnalysis aliasAnalysis, BridgedValue, BridgedInstruction); typedef bool (* _Nonnull Escaping2ValIntFn)( - BridgedPassContext context, BridgedAliasAnalysis aliasAnalysis, BridgedValue, BridgedValue); + BridgedContext context, BridgedAliasAnalysis aliasAnalysis, BridgedValue, BridgedValue); typedef bool (* _Nonnull MayAliasFn)( - BridgedPassContext context, BridgedAliasAnalysis aliasAnalysis, BridgedValue, BridgedValue); + BridgedContext context, BridgedAliasAnalysis aliasAnalysis, BridgedValue, BridgedValue); static void registerAnalysis(InitFn initFn, DestroyFn destroyFn, @@ -125,59 +119,6 @@ struct BridgedPostDomTree { BRIDGED_INLINE bool postDominates(BridgedBasicBlock dominating, BridgedBasicBlock dominated) const; }; -struct BridgedUtilities { - typedef void (* _Nonnull VerifyFunctionFn)(BridgedPassContext, BridgedFunction); - typedef void (* _Nonnull UpdateFunctionFn)(BridgedPassContext, BridgedFunction); - typedef void (* _Nonnull UpdatePhisFn)(BridgedPassContext, BridgedArrayRef); - - static void registerVerifier(VerifyFunctionFn verifyFunctionFn); - static void registerPhiUpdater(UpdateFunctionFn updateBorrowedFromFn, - UpdatePhisFn updateBorrowedFromPhisFn, - UpdatePhisFn replacePhisWithIncomingValuesFn); -}; - -struct BridgedBasicBlockSet { - swift::BasicBlockSet * _Nonnull set; - - BRIDGED_INLINE bool contains(BridgedBasicBlock block) const; - BRIDGED_INLINE bool insert(BridgedBasicBlock block) const; - BRIDGED_INLINE void erase(BridgedBasicBlock block) const; - SWIFT_IMPORT_UNSAFE BRIDGED_INLINE BridgedFunction getFunction() const; -}; - -struct BridgedNodeSet { - swift::NodeSet * _Nonnull set; - - BRIDGED_INLINE bool containsValue(BridgedValue value) const; - BRIDGED_INLINE bool insertValue(BridgedValue value) const; - BRIDGED_INLINE void eraseValue(BridgedValue value) const; - BRIDGED_INLINE bool containsInstruction(BridgedInstruction inst) const; - BRIDGED_INLINE bool insertInstruction(BridgedInstruction inst) const; - BRIDGED_INLINE void eraseInstruction(BridgedInstruction inst) const; - SWIFT_IMPORT_UNSAFE BRIDGED_INLINE BridgedFunction getFunction() const; -}; - -struct BridgedOperandSet { - swift::OperandSet * _Nonnull set; - - BRIDGED_INLINE bool contains(BridgedOperand operand) const; - BRIDGED_INLINE bool insert(BridgedOperand operand) const; - BRIDGED_INLINE void erase(BridgedOperand operand) const; - SWIFT_IMPORT_UNSAFE BRIDGED_INLINE BridgedFunction getFunction() const; -}; - -struct BridgedCloner { - swift::ClonerWithFixedLocation * _Nonnull cloner; - - BridgedCloner(BridgedGlobalVar var, BridgedPassContext context); - BridgedCloner(BridgedInstruction inst, BridgedPassContext context); - void destroy(BridgedPassContext context); - SWIFT_IMPORT_UNSAFE BridgedValue getClonedValue(BridgedValue v); - bool isValueCloned(BridgedValue v) const; - void clone(BridgedInstruction inst); - void recordFoldedValue(BridgedValue origValue, BridgedValue mappedValue); -}; - struct BridgedSpecializationCloner { swift::SpecializationCloner * _Nonnull cloner; @@ -192,20 +133,11 @@ struct BridgedSpecializationCloner { struct BridgedPassContext { swift::SwiftPassInvocation * _Nonnull invocation; - enum class SILStage { - Raw, - Canonical, - Lowered - }; + BridgedPassContext(swift::SwiftPassInvocation * _Nonnull invocation) : invocation(invocation) {} + BRIDGED_INLINE BridgedPassContext(BridgedContext ctxt); - BridgedOwnedString getModuleDescription() const; - SWIFT_IMPORT_UNSAFE BRIDGED_INLINE BridgedChangeNotificationHandler asNotificationHandler() const; - BRIDGED_INLINE void notifyDependencyOnBodyOf(BridgedFunction otherFunction) const; - BRIDGED_INLINE SILStage getSILStage() const; BRIDGED_INLINE bool hadError() const; - BRIDGED_INLINE bool moduleIsSerialized() const; - BRIDGED_INLINE bool moduleHasLoweredAddresses() const; - BRIDGED_INLINE bool isTransforming(BridgedFunction function) const; + BRIDGED_INLINE void notifyDependencyOnBodyOf(BridgedFunction otherFunction) const; // Analysis @@ -214,8 +146,6 @@ struct BridgedPassContext { SWIFT_IMPORT_UNSAFE BRIDGED_INLINE BridgedDeadEndBlocksAnalysis getDeadEndBlocksAnalysis() const; SWIFT_IMPORT_UNSAFE BRIDGED_INLINE BridgedDomTree getDomTree() const; SWIFT_IMPORT_UNSAFE BRIDGED_INLINE BridgedPostDomTree getPostDomTree() const; - SWIFT_IMPORT_UNSAFE BRIDGED_INLINE BridgedDeclObj getSwiftArrayDecl() const; - SWIFT_IMPORT_UNSAFE BRIDGED_INLINE BridgedDeclObj getSwiftMutableSpanDecl() const; // AST @@ -229,13 +159,6 @@ struct BridgedPassContext { bool cfgChanged; }; - SWIFT_IMPORT_UNSAFE BRIDGED_INLINE BridgedBasicBlock splitBlockBefore(BridgedInstruction bridgedInst) const; - SWIFT_IMPORT_UNSAFE BRIDGED_INLINE BridgedBasicBlock splitBlockAfter(BridgedInstruction bridgedInst) const; - SWIFT_IMPORT_UNSAFE BRIDGED_INLINE BridgedBasicBlock createBlockAfter(BridgedBasicBlock bridgedBlock) const; - SWIFT_IMPORT_UNSAFE BRIDGED_INLINE BridgedBasicBlock appendBlock(BridgedFunction bridgedFunction) const; - BRIDGED_INLINE void eraseInstruction(BridgedInstruction inst, bool salvageDebugInfo) const; - BRIDGED_INLINE void eraseBlock(BridgedBasicBlock block) const; - static BRIDGED_INLINE void moveInstructionBefore(BridgedInstruction inst, BridgedInstruction beforeInst); bool tryOptimizeApplyOfPartialApply(BridgedInstruction closure) const; bool tryDeleteDeadClosure(BridgedInstruction closure, bool needKeepArgsAlive) const; SWIFT_IMPORT_UNSAFE DevirtResult tryDevirtualizeApply(BridgedInstruction apply, bool isMandatory) const; @@ -256,10 +179,7 @@ struct BridgedPassContext { BridgedOwnedString mangleWithBoxToStackPromotedArgs(BridgedArrayRef bridgedPromotedArgIndices, BridgedFunction bridgedOriginalFunction) const; - SWIFT_IMPORT_UNSAFE BridgedGlobalVar createGlobalVariable(BridgedStringRef name, BridgedType type, - BridgedLinkage linkage, bool isLet) const; void inlineFunction(BridgedInstruction apply, bool mandatoryInline) const; - SWIFT_IMPORT_UNSAFE BRIDGED_INLINE BridgedValue getSILUndef(BridgedType type) const; BRIDGED_INLINE bool eliminateDeadAllocations(BridgedFunction f) const; void eraseFunction(BridgedFunction function) const; @@ -272,36 +192,12 @@ struct BridgedPassContext { SwiftInt getStaticStride(BridgedType type) const; bool canMakeStaticObjectReadOnly(BridgedType type) const; - // Sets - - SWIFT_IMPORT_UNSAFE BRIDGED_INLINE BridgedBasicBlockSet allocBasicBlockSet() const; - BRIDGED_INLINE void freeBasicBlockSet(BridgedBasicBlockSet set) const; - SWIFT_IMPORT_UNSAFE BRIDGED_INLINE BridgedNodeSet allocNodeSet() const; - BRIDGED_INLINE void freeNodeSet(BridgedNodeSet set) const; - SWIFT_IMPORT_UNSAFE BRIDGED_INLINE BridgedOperandSet allocOperandSet() const; - BRIDGED_INLINE void freeOperandSet(BridgedOperandSet set) const; - // Stack nesting BRIDGED_INLINE void notifyInvalidatedStackNesting() const; BRIDGED_INLINE bool getNeedFixStackNesting() const; void fixStackNesting(BridgedFunction function) const; - // Slabs - - struct Slab { - swift::FixedSizeSlabPayload * _Nullable data = nullptr; - - BRIDGED_INLINE static SwiftInt getCapacity(); - BRIDGED_INLINE Slab(swift::FixedSizeSlab * _Nullable slab); - BRIDGED_INLINE swift::FixedSizeSlab * _Nullable getSlab() const; - SWIFT_IMPORT_UNSAFE BRIDGED_INLINE Slab getNext() const; - SWIFT_IMPORT_UNSAFE BRIDGED_INLINE Slab getPrevious() const; - }; - - SWIFT_IMPORT_UNSAFE BRIDGED_INLINE Slab allocSlab(Slab afterSlab) const; - SWIFT_IMPORT_UNSAFE BRIDGED_INLINE Slab freeSlab(Slab slab) const; - // Access SIL module data structures SWIFT_IMPORT_UNSAFE BRIDGED_INLINE OptionalBridgedFunction getFirstFunctionInModule() const; @@ -316,61 +212,16 @@ struct BridgedPassContext { SWIFT_IMPORT_UNSAFE BRIDGED_INLINE OptionalBridgedDefaultWitnessTable getFirstDefaultWitnessTableInModule() const; SWIFT_IMPORT_UNSAFE BRIDGED_INLINE static OptionalBridgedDefaultWitnessTable getNextDefaultWitnessTableInModule( BridgedDefaultWitnessTable table); - SWIFT_IMPORT_UNSAFE BRIDGED_INLINE OptionalBridgedFunction lookupFunction(BridgedStringRef name) const; - SWIFT_IMPORT_UNSAFE BRIDGED_INLINE OptionalBridgedFunction loadFunction(BridgedStringRef name, - bool loadCalleesRecursively) const; - SWIFT_IMPORT_UNSAFE BRIDGED_INLINE - OptionalBridgedVTable lookupVTable(BridgedDeclObj classDecl) const; - SWIFT_IMPORT_UNSAFE BRIDGED_INLINE - OptionalBridgedVTable lookupSpecializedVTable(BridgedType classType) const; - SWIFT_IMPORT_UNSAFE BRIDGED_INLINE - BridgedConformance getSpecializedConformance(BridgedConformance genericConformance, - BridgedASTType type, - BridgedSubstitutionMap substitutions) const; - SWIFT_IMPORT_UNSAFE BRIDGED_INLINE - OptionalBridgedWitnessTable lookupWitnessTable(BridgedConformance conformance) const; - SWIFT_IMPORT_UNSAFE BRIDGED_INLINE BridgedWitnessTable createSpecializedWitnessTable(BridgedLinkage linkage, - bool serialized, - BridgedConformance conformance, - BridgedArrayRef bridgedEntries) const; - SWIFT_IMPORT_UNSAFE BRIDGED_INLINE BridgedVTable createSpecializedVTable(BridgedType classType, - bool serialized, - BridgedArrayRef bridgedEntries) const; - SWIFT_IMPORT_UNSAFE BRIDGED_INLINE void loadFunction(BridgedFunction function, bool loadCalleesRecursively) const; - SWIFT_IMPORT_UNSAFE OptionalBridgedFunction lookupStdlibFunction(BridgedStringRef name) const; - SWIFT_IMPORT_UNSAFE OptionalBridgedFunction lookUpNominalDeinitFunction(BridgedDeclObj nominal) const; - SWIFT_IMPORT_UNSAFE BRIDGED_INLINE BridgedSubstitutionMap getContextSubstitutionMap(BridgedType type) const; - SWIFT_IMPORT_UNSAFE BRIDGED_INLINE BridgedType getBuiltinIntegerType(SwiftInt bitWidth) const; - BRIDGED_INLINE bool calleesAreStaticallyKnowable(BridgedDeclRef method) const; - SWIFT_IMPORT_UNSAFE BridgedFunction createEmptyFunction(BridgedStringRef name, - const BridgedParameterInfo * _Nullable bridgedParams, - SwiftInt paramCount, - bool hasSelfParam, - BridgedFunction fromFunc) const; - void moveFunctionBody(BridgedFunction sourceFunc, BridgedFunction destFunc) const; // Passmanager housekeeping - BRIDGED_INLINE void beginTransformFunction(BridgedFunction function) const; - BRIDGED_INLINE void endTransformFunction() const; BRIDGED_INLINE bool continueWithNextSubpassRun(OptionalBridgedInstruction inst) const; - SWIFT_IMPORT_UNSAFE BRIDGED_INLINE BridgedPassContext initializeNestedPassContext(BridgedFunction newFunction) const; + SWIFT_IMPORT_UNSAFE BRIDGED_INLINE BridgedContext initializeNestedPassContext(BridgedFunction newFunction) const; BRIDGED_INLINE void deinitializedNestedPassContext() const; BRIDGED_INLINE void addFunctionToPassManagerWorklist(BridgedFunction newFunction, BridgedFunction oldFunction) const; - // SSAUpdater - - BRIDGED_INLINE void - SSAUpdater_initialize(BridgedFunction function, BridgedType type, - BridgedValue::Ownership ownership) const; - BRIDGED_INLINE void SSAUpdater_addAvailableValue(BridgedBasicBlock block, BridgedValue value) const; - SWIFT_IMPORT_UNSAFE BRIDGED_INLINE BridgedValue SSAUpdater_getValueAtEndOfBlock(BridgedBasicBlock block) const; - SWIFT_IMPORT_UNSAFE BRIDGED_INLINE BridgedValue SSAUpdater_getValueInMiddleOfBlock(BridgedBasicBlock block) const; - BRIDGED_INLINE SwiftInt SSAUpdater_getNumInsertedPhis() const; - SWIFT_IMPORT_UNSAFE BRIDGED_INLINE BridgedValue SSAUpdater_getInsertedPhi(SwiftInt idx) const; - // Options enum class AssertConfiguration { @@ -386,7 +237,6 @@ struct BridgedPassContext { BRIDGED_INLINE bool enableMoveInoutStackProtection() const; BRIDGED_INLINE AssertConfiguration getAssertConfiguration() const; bool enableSimplificationFor(BridgedInstruction inst) const; - SWIFT_IMPORT_UNSAFE BRIDGED_INLINE BridgedDeclObj getCurrentModuleContext() const; BRIDGED_INLINE bool enableWMORequiredDiagnostics() const; BRIDGED_INLINE bool noAllocations() const; @@ -418,23 +268,21 @@ BridgedDynamicCastResult classifyDynamicCastBridged(BridgedCanType sourceTy, Bri BridgedDynamicCastResult classifyDynamicCastBridged(BridgedInstruction inst); -void verifierError(BridgedStringRef message, OptionalBridgedInstruction atInstruction, OptionalBridgedArgument atArgument); - //===----------------------------------------------------------------------===// // Pass registration //===----------------------------------------------------------------------===// struct BridgedFunctionPassCtxt { BridgedFunction function; - BridgedPassContext passContext; + BridgedContext passContext; } ; struct BridgedInstructionPassCtxt { BridgedInstruction instruction; - BridgedPassContext passContext; + BridgedContext passContext; }; -typedef void (* _Nonnull BridgedModulePassRunFn)(BridgedPassContext); +typedef void (* _Nonnull BridgedModulePassRunFn)(BridgedContext); typedef void (* _Nonnull BridgedFunctionPassRunFn)(BridgedFunctionPassCtxt); typedef void (* _Nonnull BridgedInstructionPassRunFn)(BridgedInstructionPassCtxt); @@ -445,6 +293,9 @@ void SILPassManager_registerFunctionPass(BridgedStringRef name, void SILCombine_registerInstructionPass(BridgedStringRef instClassName, BridgedInstructionPassRunFn runFn); +void registerFunctionTestThunk(SwiftNativeFunctionTestThunk); +void registerFunctionTest(BridgedStringRef, void *_Nonnull nativeSwiftContext); + #ifndef PURE_BRIDGING_MODE // In _not_ PURE_BRIDGING_MODE, briding functions are inlined and therefore inluded in the header file. #include "OptimizerBridgingImpl.h" diff --git a/include/swift/SILOptimizer/OptimizerBridgingImpl.h b/include/swift/SILOptimizer/OptimizerBridgingImpl.h index 0db955f751770..91f560c440360 100644 --- a/include/swift/SILOptimizer/OptimizerBridgingImpl.h +++ b/include/swift/SILOptimizer/OptimizerBridgingImpl.h @@ -87,85 +87,21 @@ bool BridgedPostDomTree::postDominates(BridgedBasicBlock dominating, BridgedBasi return pdi->dominates(dominating.unbridged(), dominated.unbridged()); } -//===----------------------------------------------------------------------===// -// BridgedBasicBlockSet -//===----------------------------------------------------------------------===// - -bool BridgedBasicBlockSet::contains(BridgedBasicBlock block) const { - return set->contains(block.unbridged()); -} - -bool BridgedBasicBlockSet::insert(BridgedBasicBlock block) const { - return set->insert(block.unbridged()); -} - -void BridgedBasicBlockSet::erase(BridgedBasicBlock block) const { - set->erase(block.unbridged()); -} - -BridgedFunction BridgedBasicBlockSet::getFunction() const { - return {set->getFunction()}; -} - -//===----------------------------------------------------------------------===// -// BridgedNodeSet -//===----------------------------------------------------------------------===// - -bool BridgedNodeSet::containsValue(BridgedValue value) const { - return set->contains(value.getSILValue()); -} - -bool BridgedNodeSet::insertValue(BridgedValue value) const { - return set->insert(value.getSILValue()); -} - -void BridgedNodeSet::eraseValue(BridgedValue value) const { - set->erase(value.getSILValue()); -} - -bool BridgedNodeSet::containsInstruction(BridgedInstruction inst) const { - return set->contains(inst.unbridged()->asSILNode()); -} - -bool BridgedNodeSet::insertInstruction(BridgedInstruction inst) const { - return set->insert(inst.unbridged()->asSILNode()); -} - -void BridgedNodeSet::eraseInstruction(BridgedInstruction inst) const { - set->erase(inst.unbridged()->asSILNode()); -} - -BridgedFunction BridgedNodeSet::getFunction() const { - return {set->getFunction()}; -} - -//===----------------------------------------------------------------------===// -// BridgedOperandSet -//===----------------------------------------------------------------------===// - -bool BridgedOperandSet::contains(BridgedOperand operand) const { - return set->contains(operand.op); -} - -bool BridgedOperandSet::insert(BridgedOperand operand) const { - return set->insert(operand.op); -} - -void BridgedOperandSet::erase(BridgedOperand operand) const { - set->erase(operand.op); -} - -BridgedFunction BridgedOperandSet::getFunction() const { - return {set->getFunction()}; -} - //===----------------------------------------------------------------------===// // BridgedPassContext //===----------------------------------------------------------------------===// -BridgedChangeNotificationHandler BridgedPassContext::asNotificationHandler() const { - return {invocation}; -} +static_assert((int)swift::SILAnalysis::InvalidationKind::Instructions == + (int)swift::SILContext::NotificationKind::Instructions); +static_assert((int)swift::SILAnalysis::InvalidationKind::Calls == + (int)swift::SILContext::NotificationKind::Calls); +static_assert((int)swift::SILAnalysis::InvalidationKind::Branches == + (int)swift::SILContext::NotificationKind::Branches); +static_assert((int)swift::SILAnalysis::InvalidationKind::Effects == + (int)swift::SILContext::NotificationKind::Effects); + +BridgedPassContext::BridgedPassContext(BridgedContext ctxt) : + invocation(static_cast(ctxt.context)) {} void BridgedPassContext::notifyDependencyOnBodyOf(BridgedFunction otherFunction) const { // Currently `otherFunction` is ignored. We could design a more accurate dependency system @@ -173,26 +109,10 @@ void BridgedPassContext::notifyDependencyOnBodyOf(BridgedFunction otherFunction) invocation->getPassManager()->setDependingOnCalleeBodies(); } -BridgedPassContext::SILStage BridgedPassContext::getSILStage() const { - return (SILStage)invocation->getPassManager()->getModule()->getStage(); -} - bool BridgedPassContext::hadError() const { return invocation->getPassManager()->getModule()->getASTContext().hadError(); } -bool BridgedPassContext::moduleIsSerialized() const { - return invocation->getPassManager()->getModule()->isSerialized(); -} - -bool BridgedPassContext::moduleHasLoweredAddresses() const { - return invocation->getPassManager()->getModule()->useLoweredAddresses(); -} - -bool BridgedPassContext::isTransforming(BridgedFunction function) const { - return invocation->getFunction() == function.getFunction(); -} - BridgedAliasAnalysis BridgedPassContext::getAliasAnalysis() const { return {invocation->getPassManager()->getAnalysis(invocation->getFunction())}; } @@ -216,16 +136,6 @@ BridgedPostDomTree BridgedPassContext::getPostDomTree() const { return {pda->get(invocation->getFunction())}; } -BridgedDeclObj BridgedPassContext::getSwiftArrayDecl() const { - swift::SILModule *mod = invocation->getPassManager()->getModule(); - return {mod->getASTContext().getArrayDecl()}; -} - -BridgedDeclObj BridgedPassContext::getSwiftMutableSpanDecl() const { - swift::SILModule *mod = invocation->getPassManager()->getModule(); - return {mod->getASTContext().getMutableSpanDecl()}; -} - // AST SWIFT_IMPORT_UNSAFE BRIDGED_INLINE @@ -236,111 +146,11 @@ BridgedDiagnosticEngine BridgedPassContext::getDiagnosticEngine() const { // SIL modifications -BridgedBasicBlock BridgedPassContext::splitBlockBefore(BridgedInstruction bridgedInst) const { - auto *block = bridgedInst.unbridged()->getParent(); - return {block->split(bridgedInst.unbridged()->getIterator())}; -} - -BridgedBasicBlock BridgedPassContext::splitBlockAfter(BridgedInstruction bridgedInst) const { - auto *block = bridgedInst.unbridged()->getParent(); - return {block->split(std::next(bridgedInst.unbridged()->getIterator()))}; -} - -BridgedBasicBlock BridgedPassContext::createBlockAfter(BridgedBasicBlock bridgedBlock) const { - swift::SILBasicBlock *block = bridgedBlock.unbridged(); - return {block->getParent()->createBasicBlockAfter(block)}; -} - -BridgedBasicBlock BridgedPassContext::appendBlock(BridgedFunction bridgedFunction) const { - return {bridgedFunction.getFunction()->createBasicBlock()}; -} - -void BridgedPassContext::eraseInstruction(BridgedInstruction inst, bool salvageDebugInfo) const { - invocation->eraseInstruction(inst.unbridged(), salvageDebugInfo); -} - -void BridgedPassContext::eraseBlock(BridgedBasicBlock block) const { - block.unbridged()->eraseFromParent(); -} - -void BridgedPassContext::moveInstructionBefore(BridgedInstruction inst, BridgedInstruction beforeInst) { - swift::SILBasicBlock::moveInstruction(inst.unbridged(), beforeInst.unbridged()); -} - -BridgedValue BridgedPassContext::getSILUndef(BridgedType type) const { - return {swift::SILUndef::get(invocation->getFunction(), type.unbridged())}; -} - bool BridgedPassContext::eliminateDeadAllocations(BridgedFunction f) const { return swift::eliminateDeadAllocations(f.getFunction(), this->getDomTree().di); } -BridgedBasicBlockSet BridgedPassContext::allocBasicBlockSet() const { - return {invocation->allocBlockSet()}; -} - -void BridgedPassContext::freeBasicBlockSet(BridgedBasicBlockSet set) const { - invocation->freeBlockSet(set.set); -} - -BridgedNodeSet BridgedPassContext::allocNodeSet() const { - return {invocation->allocNodeSet()}; -} - -void BridgedPassContext::freeNodeSet(BridgedNodeSet set) const { - invocation->freeNodeSet(set.set); -} - -BridgedOperandSet BridgedPassContext::allocOperandSet() const { - return {invocation->allocOperandSet()}; -} - -void BridgedPassContext::freeOperandSet(BridgedOperandSet set) const { - invocation->freeOperandSet(set.set); -} - -void BridgedPassContext::notifyInvalidatedStackNesting() const { - invocation->setNeedFixStackNesting(true); -} - -bool BridgedPassContext::getNeedFixStackNesting() const { - return invocation->getNeedFixStackNesting(); -} - -SwiftInt BridgedPassContext::Slab::getCapacity() { - return (SwiftInt)swift::FixedSizeSlabPayload::capacity; -} - -BridgedPassContext::Slab::Slab(swift::FixedSizeSlab * _Nullable slab) { - if (slab) { - data = slab; - assert((void *)data == slab->dataFor()); - } -} - -swift::FixedSizeSlab * _Nullable BridgedPassContext::Slab::getSlab() const { - if (data) - return static_cast(data); - return nullptr; -} - -BridgedPassContext::Slab BridgedPassContext::Slab::getNext() const { - return &*std::next(getSlab()->getIterator()); -} - -BridgedPassContext::Slab BridgedPassContext::Slab::getPrevious() const { - return &*std::prev(getSlab()->getIterator()); -} - -BridgedPassContext::Slab BridgedPassContext::allocSlab(Slab afterSlab) const { - return invocation->allocSlab(afterSlab.getSlab()); -} - -BridgedPassContext::Slab BridgedPassContext::freeSlab(Slab slab) const { - return invocation->freeSlab(slab.getSlab()); -} - OptionalBridgedFunction BridgedPassContext::getFirstFunctionInModule() const { swift::SILModule *mod = invocation->getPassManager()->getModule(); if (mod->getFunctions().empty()) @@ -410,106 +220,12 @@ getNextDefaultWitnessTableInModule(BridgedDefaultWitnessTable table) { return {&*nextIter}; } -OptionalBridgedFunction BridgedPassContext::lookupFunction(BridgedStringRef name) const { - swift::SILModule *mod = invocation->getPassManager()->getModule(); - return {mod->lookUpFunction(name.unbridged())}; -} - -OptionalBridgedFunction BridgedPassContext::loadFunction(BridgedStringRef name, bool loadCalleesRecursively) const { - swift::SILModule *mod = invocation->getPassManager()->getModule(); - return {mod->loadFunction(name.unbridged(), - loadCalleesRecursively - ? swift::SILModule::LinkingMode::LinkAll - : swift::SILModule::LinkingMode::LinkNormal)}; -} - -OptionalBridgedVTable BridgedPassContext::lookupVTable(BridgedDeclObj classDecl) const { - swift::SILModule *mod = invocation->getPassManager()->getModule(); - return {mod->lookUpVTable(classDecl.getAs())}; -} - -OptionalBridgedVTable BridgedPassContext::lookupSpecializedVTable(BridgedType classType) const { - swift::SILModule *mod = invocation->getPassManager()->getModule(); - return {mod->lookUpSpecializedVTable(classType.unbridged())}; -} - -BridgedConformance BridgedPassContext::getSpecializedConformance( - BridgedConformance genericConformance, - BridgedASTType type, - BridgedSubstitutionMap substitutions) const { - auto &ctxt = invocation->getPassManager()->getModule()->getASTContext(); - auto *genConf = llvm::cast(genericConformance.unbridged().getConcrete()); - auto *c = ctxt.getSpecializedConformance(type.unbridged(), genConf, substitutions.unbridged()); - return swift::ProtocolConformanceRef(c); -} - -OptionalBridgedWitnessTable BridgedPassContext::lookupWitnessTable(BridgedConformance conformance) const { - swift::ProtocolConformanceRef ref = conformance.unbridged(); - if (!ref.isConcrete()) { - return {nullptr}; - } - swift::SILModule *mod = invocation->getPassManager()->getModule(); - return {mod->lookUpWitnessTable(ref.getConcrete())}; -} - -BridgedWitnessTable BridgedPassContext::createSpecializedWitnessTable(BridgedLinkage linkage, - bool serialized, - BridgedConformance conformance, - BridgedArrayRef bridgedEntries) const { - swift::SILModule *mod = invocation->getPassManager()->getModule(); - llvm::SmallVector entries; - for (const BridgedWitnessTableEntry &e : bridgedEntries.unbridged()) { - entries.push_back(e.unbridged()); - } - return {swift::SILWitnessTable::create(*mod, (swift::SILLinkage)linkage, - serialized ? swift::IsSerialized : swift::IsNotSerialized, - conformance.unbridged().getConcrete(), - entries, {}, /*specialized=*/true)}; -} - -BridgedVTable BridgedPassContext::createSpecializedVTable(BridgedType classType, - bool serialized, - BridgedArrayRef bridgedEntries) const { - swift::SILModule *mod = invocation->getPassManager()->getModule(); - llvm::SmallVector entries; - for (const BridgedVTableEntry &e : bridgedEntries.unbridged()) { - entries.push_back(e.unbridged()); - } - swift::SILType classTy = classType.unbridged(); - return {swift::SILVTable::create(*mod, - classTy.getClassOrBoundGenericClass(), classTy, - serialized ? swift::IsSerialized : swift::IsNotSerialized, - entries)}; -} - -void BridgedPassContext::loadFunction(BridgedFunction function, bool loadCalleesRecursively) const { - swift::SILModule *mod = invocation->getPassManager()->getModule(); - mod->loadFunction(function.getFunction(), - loadCalleesRecursively ? swift::SILModule::LinkingMode::LinkAll - : swift::SILModule::LinkingMode::LinkNormal); -} - -BridgedSubstitutionMap BridgedPassContext::getContextSubstitutionMap(BridgedType type) const { - swift::SILType ty = type.unbridged(); - return ty.getASTType()->getContextSubstitutionMap(); -} - -BridgedType BridgedPassContext::getBuiltinIntegerType(SwiftInt bitWidth) const { - auto &ctxt = invocation->getPassManager()->getModule()->getASTContext(); - return swift::SILType::getBuiltinIntegerType(bitWidth, ctxt); -} - -bool BridgedPassContext::calleesAreStaticallyKnowable(BridgedDeclRef method) const { - swift::SILModule *mod = invocation->getPassManager()->getModule(); - return swift::calleesAreStaticallyKnowable(*mod, method.unbridged()); -} - -void BridgedPassContext::beginTransformFunction(BridgedFunction function) const { - invocation->beginTransformFunction(function.getFunction()); +void BridgedPassContext::notifyInvalidatedStackNesting() const { + invocation->setNeedFixStackNesting(true); } -void BridgedPassContext::endTransformFunction() const { - invocation->endTransformFunction(); +bool BridgedPassContext::getNeedFixStackNesting() const { + return invocation->getNeedFixStackNesting(); } bool BridgedPassContext::continueWithNextSubpassRun(OptionalBridgedInstruction inst) const { @@ -518,21 +234,14 @@ bool BridgedPassContext::continueWithNextSubpassRun(OptionalBridgedInstruction i inst.unbridged(), invocation->getFunction(), invocation->getTransform()); } -BridgedPassContext BridgedPassContext::initializeNestedPassContext(BridgedFunction newFunction) const { - return { invocation->initializeNestedSwiftPassInvocation(newFunction.getFunction()) }; +BridgedContext BridgedPassContext::initializeNestedPassContext(BridgedFunction newFunction) const { + return { invocation->initializeNestedSwiftPassInvocation(newFunction.getFunction()) }; } void BridgedPassContext::deinitializedNestedPassContext() const { invocation->deinitializeNestedSwiftPassInvocation(); } -void BridgedPassContext::SSAUpdater_initialize( - BridgedFunction function, BridgedType type, - BridgedValue::Ownership ownership) const { - invocation->initializeSSAUpdater(function.getFunction(), type.unbridged(), - BridgedValue::unbridge(ownership)); -} - void BridgedPassContext::addFunctionToPassManagerWorklist( BridgedFunction newFunction, BridgedFunction oldFunction) const { swift::SILPassManager *pm = invocation->getPassManager(); @@ -541,28 +250,6 @@ void BridgedPassContext::addFunctionToPassManagerWorklist( } } -void BridgedPassContext::SSAUpdater_addAvailableValue(BridgedBasicBlock block, BridgedValue value) const { - invocation->getSSAUpdater()->addAvailableValue(block.unbridged(), - value.getSILValue()); -} - -BridgedValue BridgedPassContext::SSAUpdater_getValueAtEndOfBlock(BridgedBasicBlock block) const { - return {invocation->getSSAUpdater()->getValueAtEndOfBlock(block.unbridged())}; -} - -BridgedValue BridgedPassContext::SSAUpdater_getValueInMiddleOfBlock(BridgedBasicBlock block) const { - return { - invocation->getSSAUpdater()->getValueInMiddleOfBlock(block.unbridged())}; -} - -SwiftInt BridgedPassContext::SSAUpdater_getNumInsertedPhis() const { - return (SwiftInt)invocation->getInsertedPhisBySSAUpdater().size(); -} - -BridgedValue BridgedPassContext::SSAUpdater_getInsertedPhi(SwiftInt idx) const { - return {invocation->getInsertedPhisBySSAUpdater()[idx]}; -} - bool BridgedPassContext::enableStackProtection() const { swift::SILModule *mod = invocation->getPassManager()->getModule(); return mod->getOptions().EnableStackProtection; @@ -598,10 +285,6 @@ bool BridgedPassContext::shouldExpand(BridgedType ty) const { return swift::shouldExpand(mod, ty.unbridged()); } -BridgedDeclObj BridgedPassContext::getCurrentModuleContext() const { - return {invocation->getPassManager()->getModule()->getSwiftModule()}; -} - bool BridgedPassContext::enableWMORequiredDiagnostics() const { swift::SILModule *mod = invocation->getPassManager()->getModule(); return mod->getOptions().EnableWMORequiredDiagnostics; @@ -617,10 +300,6 @@ bool BridgedPassContext::enableAddressDependencies() const { return mod->getOptions().EnableAddressDependencies; } -static_assert((int)BridgedPassContext::SILStage::Raw == (int)swift::SILStage::Raw); -static_assert((int)BridgedPassContext::SILStage::Canonical == (int)swift::SILStage::Canonical); -static_assert((int)BridgedPassContext::SILStage::Lowered == (int)swift::SILStage::Lowered); - static_assert((int)BridgedPassContext::AssertConfiguration::Debug == (int)swift::SILOptions::Debug); static_assert((int)BridgedPassContext::AssertConfiguration::Release == (int)swift::SILOptions::Release); static_assert((int)BridgedPassContext::AssertConfiguration::Unchecked == (int)swift::SILOptions::Unchecked); diff --git a/include/swift/SILOptimizer/PassManager/PassManager.h b/include/swift/SILOptimizer/PassManager/PassManager.h index b46f47ba662bd..ca4a88399d7b9 100644 --- a/include/swift/SILOptimizer/PassManager/PassManager.h +++ b/include/swift/SILOptimizer/PassManager/PassManager.h @@ -18,7 +18,6 @@ #include "swift/SILOptimizer/Analysis/Analysis.h" #include "swift/SILOptimizer/PassManager/PassPipeline.h" #include "swift/SILOptimizer/PassManager/Passes.h" -#include "swift/SILOptimizer/Utils/SILSSAUpdater.h" #include "llvm/ADT/DenseMap.h" #include "llvm/ADT/SmallVector.h" #include "llvm/Support/Casting.h" @@ -52,67 +51,36 @@ void executePassPipelinePlan(SILModule *SM, const SILPassPipelinePlan &plan, irgen::IRGenModule *IRMod = nullptr); /// Utility class to invoke Swift passes. -class SwiftPassInvocation { +class SwiftPassInvocation : public SILContext { /// Backlink to the pass manager. SILPassManager *passManager; /// The current transform. SILTransform *transform = nullptr; - /// The currently optimized function. - SILFunction *function = nullptr; - - /// Non-null if this is an instruction pass, invoked from SILCombine. + /// Non-null if this is an instruction simplification, invoked from SILCombine. SILCombiner *silCombiner = nullptr; - /// Change notifications, collected during a pass run. - SILAnalysis::InvalidationKind changeNotifications = - SILAnalysis::InvalidationKind::Nothing; - - bool functionTablesChanged = false; - - /// All slabs, allocated by the pass. - SILModule::SlabList allocatedSlabs; - - SILSSAUpdater *ssaUpdater = nullptr; - SmallVector insertedPhisBySSAUpdater; - SwiftPassInvocation *nestedSwiftPassInvocation = nullptr; - static constexpr int BlockSetCapacity = SILBasicBlock::numCustomBits; - char blockSetStorage[sizeof(BasicBlockSet) * BlockSetCapacity]; - bool aliveBlockSets[BlockSetCapacity]; - int numBlockSetsAllocated = 0; - - static constexpr int NodeSetCapacity = SILNode::numCustomBits; - char nodeSetStorage[sizeof(NodeSet) * NodeSetCapacity]; - bool aliveNodeSets[NodeSetCapacity]; - int numNodeSetsAllocated = 0; - - static constexpr int OperandSetCapacity = Operand::numCustomBits; - char operandSetStorage[sizeof(OperandSet) * OperandSetCapacity]; - bool aliveOperandSets[OperandSetCapacity]; - int numOperandSetsAllocated = 0; - - int numClonersAllocated = 0; - bool needFixStackNesting = false; + void verifyEverythingIsCleared(); + void endPass(); public: SwiftPassInvocation(SILPassManager *passManager, SILFunction *function, SILCombiner *silCombiner) : - passManager(passManager), function(function), silCombiner(silCombiner) {} + SILContext(function), passManager(passManager), silCombiner(silCombiner) {} SwiftPassInvocation(SILPassManager *passManager, SILTransform *transform, SILFunction *function) : - passManager(passManager), transform(transform), function(function) {} + SILContext(function), passManager(passManager), transform(transform) {} - SwiftPassInvocation(SILPassManager *passManager) : - passManager(passManager) {} + SwiftPassInvocation(SILPassManager *passManager); - ~SwiftPassInvocation(); + virtual ~SwiftPassInvocation(); SILPassManager *getPassManager() const { return passManager; } @@ -122,29 +90,20 @@ class SwiftPassInvocation { irgen::IRGenModule *getIRGenModule(); - FixedSizeSlab *allocSlab(FixedSizeSlab *afterSlab); - - FixedSizeSlab *freeSlab(FixedSizeSlab *slab); - - BasicBlockSet *allocBlockSet(); - - void freeBlockSet(BasicBlockSet *set); - - NodeSet *allocNodeSet(); - - void freeNodeSet(NodeSet *set); - - OperandSet *allocOperandSet(); + /// The top-level API to erase an instruction, called from the Swift pass. + void eraseInstruction(SILInstruction *inst, bool salvageDebugInfo) override; - void freeOperandSet(OperandSet *set); + SILFunction *createEmptyFunction(StringRef name, ArrayRef params, + bool hasSelfParam, SILFunction *fromFn) override; - /// The top-level API to erase an instruction, called from the Swift pass. - void eraseInstruction(SILInstruction *inst, bool salvageDebugInfo); + void moveFunctionBody(SILFunction *sourceFn, SILFunction *destFn) override; - /// Called by the pass when changes are made to the SIL. - void notifyChanges(SILAnalysis::InvalidationKind invalidationKind); + SILFunction *lookupStdlibFunction(StringRef name) override; - void notifyFunctionTablesChanged(); + void initializeSSAUpdater(SILFunction *function, SILType type, ValueOwnershipKind ownership) override; + void SSAUpdater_addAvailableValue(SILBasicBlock *block, SILValue value) override; + SILValue SSAUpdater_getValueAtEndOfBlock(SILBasicBlock *block) override; + SILValue SSAUpdater_getValueInMiddleOfBlock(SILBasicBlock *block) override; /// Called by the pass manager before the pass starts running. void startModulePassRun(SILModuleTransform *transform); @@ -164,34 +123,12 @@ class SwiftPassInvocation { /// Called by the SILCombiner when the instruction pass has finished. void finishedInstructionPassRun(); - void beginTransformFunction(SILFunction *function); - - void endTransformFunction(); - void beginVerifyFunction(SILFunction *function); void endVerifyFunction(); - void notifyNewCloner() { numClonersAllocated++; } - void notifyClonerDestroyed() { numClonersAllocated--; } - void setNeedFixStackNesting(bool newValue) { needFixStackNesting = newValue; } bool getNeedFixStackNesting() const { return needFixStackNesting; } - void initializeSSAUpdater(SILFunction *fn, SILType type, - ValueOwnershipKind ownership) { - insertedPhisBySSAUpdater.clear(); - if (!ssaUpdater) - ssaUpdater = new SILSSAUpdater(&insertedPhisBySSAUpdater); - ssaUpdater->initialize(fn, type, ownership); - } - - SILSSAUpdater *getSSAUpdater() const { - assert(ssaUpdater && "SSAUpdater not initialized"); - return ssaUpdater; - } - - ArrayRef getInsertedPhisBySSAUpdater() { return insertedPhisBySSAUpdater; } - SwiftPassInvocation *initializeNestedSwiftPassInvocation(SILFunction *newFunction) { assert(!nestedSwiftPassInvocation && "Nested Swift pass invocation already initialized"); nestedSwiftPassInvocation = new SwiftPassInvocation(passManager, transform, newFunction); @@ -200,7 +137,7 @@ class SwiftPassInvocation { void deinitializeNestedSwiftPassInvocation() { assert(nestedSwiftPassInvocation && "Nested Swift pass invocation not initialized"); - nestedSwiftPassInvocation->endTransformFunction(); + nestedSwiftPassInvocation->finishedFunctionPassRun(); delete nestedSwiftPassInvocation; nestedSwiftPassInvocation = nullptr; } @@ -518,14 +455,8 @@ class SILPassManager { void viewCallGraph(); }; -inline void SwiftPassInvocation:: -notifyChanges(SILAnalysis::InvalidationKind invalidationKind) { - changeNotifications = (SILAnalysis::InvalidationKind) - (changeNotifications | invalidationKind); -} -inline void SwiftPassInvocation::notifyFunctionTablesChanged() { - functionTablesChanged = true; -} +inline SwiftPassInvocation::SwiftPassInvocation(SILPassManager *passManager) : + SILContext(passManager->getModule()), passManager(passManager) {} } // end namespace swift diff --git a/lib/SIL/Utils/SILBridging.cpp b/lib/SIL/Utils/SILBridging.cpp index 994d9bc8f4ffb..8f6f390f0aaf3 100644 --- a/lib/SIL/Utils/SILBridging.cpp +++ b/lib/SIL/Utils/SILBridging.cpp @@ -20,6 +20,8 @@ #include "swift/AST/Attr.h" #include "swift/AST/SemanticAttrs.h" #include "swift/Basic/Assertions.h" +#include "swift/SIL/SILContext.h" +#include "swift/SIL/SILCloner.h" #include "swift/SIL/MemAccessUtils.h" #include "swift/SIL/OwnershipUtils.h" #include "swift/SIL/ParseTestSpecification.h" @@ -125,9 +127,9 @@ void registerBridgedClass(BridgedStringRef bridgedClassName, SwiftMetatype metat // Test //===----------------------------------------------------------------------===// -void registerFunctionTest(BridgedStringRef name, void *nativeSwiftInvocation) { +void registerTest(BridgedStringRef name, void *nativeSwiftContext) { swift::test::FunctionTest::createNativeSwiftFunctionTest( - name.unbridged(), nativeSwiftInvocation); + name.unbridged(), nativeSwiftContext, /*isSILTest=*/ true); } bool BridgedTestArguments::hasUntaken() const { @@ -542,3 +544,257 @@ BridgedInstruction BridgedBuilder::createSwitchEnumAddrInst(BridgedValue enumAdd defaultBlock.unbridged(), convertCases(enumAddr.getSILValue()->getType(), enumCases, numEnumCases))}; } + +//===----------------------------------------------------------------------===// +// BridgedCloner +//===----------------------------------------------------------------------===// + +// Need to put ClonerWithFixedLocation into namespace swift to forward reference +// it in SILBridging.h. +namespace swift { + +class ClonerWithFixedLocation : public SILCloner { + friend class SILInstructionVisitor; + friend class SILCloner; + + SILDebugLocation insertLoc; + +public: + ClonerWithFixedLocation(SILGlobalVariable *gVar) + : SILCloner(gVar), + insertLoc(ArtificialUnreachableLocation(), nullptr) {} + + ClonerWithFixedLocation(SILInstruction *insertionPoint) + : SILCloner(*insertionPoint->getFunction()), + insertLoc(insertionPoint->getDebugLocation()) { + Builder.setInsertionPoint(insertionPoint); + } + + SILValue getClonedValue(SILValue v) { + return getMappedValue(v); + } + + void cloneInst(SILInstruction *inst) { + visit(inst); + } + +protected: + + SILLocation remapLocation(SILLocation loc) { + return insertLoc.getLocation(); + } + + const SILDebugScope *remapScope(const SILDebugScope *DS) { + return insertLoc.getScope(); + } +}; + +} // namespace swift + +BridgedCloner::BridgedCloner(BridgedGlobalVar var, BridgedContext context) + : cloner(new ClonerWithFixedLocation(var.getGlobal())) { + context.context->notifyNewCloner(); +} + +BridgedCloner::BridgedCloner(BridgedInstruction inst, + BridgedContext context) + : cloner(new ClonerWithFixedLocation(inst.unbridged())) { + context.context->notifyNewCloner(); +} + +void BridgedCloner::destroy(BridgedContext context) { + delete cloner; + cloner = nullptr; + context.context->notifyClonerDestroyed(); +} + +BridgedValue BridgedCloner::getClonedValue(BridgedValue v) { + return {cloner->getClonedValue(v.getSILValue())}; +} + +bool BridgedCloner::isValueCloned(BridgedValue v) const { + return cloner->isValueCloned(v.getSILValue()); +} + +void BridgedCloner::clone(BridgedInstruction inst) { + cloner->cloneInst(inst.unbridged()); +} + +void BridgedCloner::recordFoldedValue(BridgedValue origValue, BridgedValue mappedValue) { + cloner->recordFoldedValue(origValue.getSILValue(), mappedValue.getSILValue()); +} + +//===----------------------------------------------------------------------===// +// BridgedContext +//===----------------------------------------------------------------------===// + +BridgedOwnedString BridgedContext::getModuleDescription() const { + std::string str; + llvm::raw_string_ostream os(str); + context->getModule()->print(os); + str.pop_back(); // Remove trailing newline. + return BridgedOwnedString(str); +} + +OptionalBridgedFunction BridgedContext::lookUpNominalDeinitFunction(BridgedDeclObj nominal) const { + return {context->getModule()->lookUpMoveOnlyDeinitFunction(nominal.getAs())}; +} + +BridgedFunction BridgedContext:: +createEmptyFunction(BridgedStringRef name, + const BridgedParameterInfo * _Nullable bridgedParams, + SwiftInt paramCount, + bool hasSelfParam, + BridgedFunction fromFunc) const { + llvm::SmallVector params; + for (unsigned idx = 0; idx < paramCount; ++idx) { + params.push_back(bridgedParams[idx].unbridged()); + } + return {context->createEmptyFunction(name.unbridged(), params, hasSelfParam, fromFunc.getFunction())}; +} + +BridgedGlobalVar BridgedContext::createGlobalVariable(BridgedStringRef name, BridgedType type, + BridgedLinkage linkage, bool isLet) const { + auto *global = SILGlobalVariable::create( + *context->getModule(), + (swift::SILLinkage)linkage, IsNotSerialized, + name.unbridged(), type.unbridged()); + if (isLet) + global->setLet(true); + return {global}; +} + +void BridgedContext::moveFunctionBody(BridgedFunction sourceFunc, BridgedFunction destFunc) const { + context->moveFunctionBody(sourceFunc.getFunction(), destFunc.getFunction()); +} + +//===----------------------------------------------------------------------===// +// SILContext +//===----------------------------------------------------------------------===// + +SILContext::~SILContext() {} + +void SILContext::verifyEverythingIsCleared() { + ASSERT(allocatedSlabs.empty() && "StackList is leaking slabs"); + ASSERT(numBlockSetsAllocated == 0 && "Not all BasicBlockSets deallocated"); + ASSERT(numNodeSetsAllocated == 0 && "Not all NodeSets deallocated"); + ASSERT(numOperandSetsAllocated == 0 && "Not all OperandSets deallocated"); + ASSERT(numClonersAllocated == 0 && "Not all cloners deallocated"); +} + +FixedSizeSlab *SILContext::allocSlab(FixedSizeSlab *afterSlab) { + FixedSizeSlab *slab = getModule()->allocSlab(); + if (afterSlab) { + allocatedSlabs.insert(std::next(afterSlab->getIterator()), *slab); + } else { + allocatedSlabs.push_back(*slab); + } + return slab; +} + +FixedSizeSlab *SILContext::freeSlab(FixedSizeSlab *slab) { + FixedSizeSlab *prev = nullptr; + assert(!allocatedSlabs.empty()); + if (&allocatedSlabs.front() != slab) + prev = &*std::prev(slab->getIterator()); + + allocatedSlabs.remove(*slab); + getModule()->freeSlab(slab); + return prev; +} + +BasicBlockSet *SILContext::allocBlockSet() { + ASSERT(numBlockSetsAllocated < BlockSetCapacity && + "too many BasicBlockSets allocated"); + + auto *storage = (BasicBlockSet *)blockSetStorage + numBlockSetsAllocated; + BasicBlockSet *set = new (storage) BasicBlockSet(function); + aliveBlockSets[numBlockSetsAllocated] = true; + ++numBlockSetsAllocated; + return set; +} + +void SILContext::freeBlockSet(BasicBlockSet *set) { + int idx = set - (BasicBlockSet *)blockSetStorage; + assert(idx >= 0 && idx < numBlockSetsAllocated); + assert(aliveBlockSets[idx] && "double free of BasicBlockSet"); + aliveBlockSets[idx] = false; + + while (numBlockSetsAllocated > 0 && !aliveBlockSets[numBlockSetsAllocated - 1]) { + auto *set = (BasicBlockSet *)blockSetStorage + numBlockSetsAllocated - 1; + set->~BasicBlockSet(); + --numBlockSetsAllocated; + } +} + +NodeSet *SILContext::allocNodeSet() { + ASSERT(numNodeSetsAllocated < NodeSetCapacity && + "too many NodeSets allocated"); + + auto *storage = (NodeSet *)nodeSetStorage + numNodeSetsAllocated; + NodeSet *set = new (storage) NodeSet(function); + aliveNodeSets[numNodeSetsAllocated] = true; + ++numNodeSetsAllocated; + return set; +} + +void SILContext::freeNodeSet(NodeSet *set) { + int idx = set - (NodeSet *)nodeSetStorage; + assert(idx >= 0 && idx < numNodeSetsAllocated); + assert(aliveNodeSets[idx] && "double free of NodeSet"); + aliveNodeSets[idx] = false; + + while (numNodeSetsAllocated > 0 && !aliveNodeSets[numNodeSetsAllocated - 1]) { + auto *set = (NodeSet *)nodeSetStorage + numNodeSetsAllocated - 1; + set->~NodeSet(); + --numNodeSetsAllocated; + } +} + +OperandSet *SILContext::allocOperandSet() { + ASSERT(numOperandSetsAllocated < OperandSetCapacity && + "too many OperandSets allocated"); + + auto *storage = (OperandSet *)operandSetStorage + numOperandSetsAllocated; + OperandSet *set = new (storage) OperandSet(function); + aliveOperandSets[numOperandSetsAllocated] = true; + ++numOperandSetsAllocated; + return set; +} + +void SILContext::freeOperandSet(OperandSet *set) { + int idx = set - (OperandSet *)operandSetStorage; + assert(idx >= 0 && idx < numOperandSetsAllocated); + assert(aliveOperandSets[idx] && "double free of OperandSet"); + aliveOperandSets[idx] = false; + + while (numOperandSetsAllocated > 0 && !aliveOperandSets[numOperandSetsAllocated - 1]) { + auto *set = (OperandSet *)operandSetStorage + numOperandSetsAllocated - 1; + set->~OperandSet(); + --numOperandSetsAllocated; + } +} + +//===----------------------------------------------------------------------===// +// BridgedVerifier +//===----------------------------------------------------------------------===// + +static BridgedVerifier::VerifyFunctionFn verifyFunctionFunction = nullptr; + +void BridgedVerifier::registerVerifier(VerifyFunctionFn verifyFunctionFn) { + verifyFunctionFunction = verifyFunctionFn; +} + +void BridgedVerifier::runSwiftFunctionVerification(SILFunction * _Nonnull f, SILContext * _Nonnull context) { + if (!verifyFunctionFunction) + return; + + verifyFunctionFunction({context}, {f}); +} + +void BridgedVerifier::verifierError(BridgedStringRef message, + OptionalBridgedInstruction atInstruction, + OptionalBridgedArgument atArgument) { + Twine msg(message.unbridged()); + verificationFailure(msg, atInstruction.unbridged(), atArgument.unbridged(), /*extraContext=*/nullptr); +} diff --git a/lib/SIL/Utils/Test.cpp b/lib/SIL/Utils/Test.cpp index 4a9eb94a6d61c..2c3d7911d068f 100644 --- a/lib/SIL/Utils/Test.cpp +++ b/lib/SIL/Utils/Test.cpp @@ -27,7 +27,8 @@ namespace { class Registry { StringMap registeredTests; - SwiftNativeFunctionTestThunk thunk; + SwiftNativeFunctionTestThunk functionTestThunk; + SwiftNativeFunctionTestThunk silTestThunk; public: static Registry &get() { @@ -41,11 +42,17 @@ class Registry { (void)inserted; } + void registerFunctionTestThunk(SwiftNativeFunctionTestThunk thunk) { - this->thunk = thunk; + this->functionTestThunk = thunk; + } + + void registerTestThunk(SwiftNativeFunctionTestThunk thunk) { + this->silTestThunk = thunk; } - SwiftNativeFunctionTestThunk getFunctionTestThunk() { return thunk; } + SwiftNativeFunctionTestThunk getFunctionTestThunk() { return functionTestThunk; } + SwiftNativeFunctionTestThunk getSILTestThunk() { return silTestThunk; } FunctionTest getFunctionTest(StringRef name) { auto iter = registeredTests.find(name); @@ -75,18 +82,23 @@ void registerFunctionTestThunk(SwiftNativeFunctionTestThunk thunk) { Registry::get().registerFunctionTestThunk(thunk); } +void registerTestThunk(SwiftNativeFunctionTestThunk thunk) { + Registry::get().registerTestThunk(thunk); +} + FunctionTest::FunctionTest(StringRef name, Invocation invocation) : invocation(invocation), pass(nullptr), function(nullptr), dependencies(nullptr) { Registry::get().registerFunctionTest(*this, name); } -FunctionTest::FunctionTest(StringRef name, NativeSwiftInvocation invocation) - : invocation(invocation), pass(nullptr), function(nullptr), - dependencies(nullptr) {} +FunctionTest::FunctionTest(StringRef name, NativeSwiftInvocation invocation, + bool isSILTest) + : invocation(invocation), isSwiftSILTest(isSILTest), pass(nullptr), + function(nullptr), dependencies(nullptr) {} void FunctionTest::createNativeSwiftFunctionTest( - StringRef name, NativeSwiftInvocation invocation) { - Registry::get().registerFunctionTest({name, invocation}, name); + StringRef name, NativeSwiftInvocation invocation, bool isSILTest) { + Registry::get().registerFunctionTest({name, invocation, isSILTest}, name); } FunctionTest FunctionTest::get(StringRef name) { @@ -104,8 +116,9 @@ void FunctionTest::run(SILFunction &function, Arguments &arguments, } else { llvm::outs().flush(); auto *fn = invocation.get(); - Registry::get().getFunctionTestThunk()(fn, {&function}, {&arguments}, - {getSwiftPassInvocation()}); + auto thunk = isSwiftSILTest ? Registry::get().getSILTestThunk() + : Registry::get().getFunctionTestThunk(); + thunk(fn, {&function}, {&arguments}, {getSILContext()}); fflush(stdout); } this->pass = nullptr; @@ -125,6 +138,6 @@ SILPassManager *FunctionTest::getPassManager() { return dependencies->getPassManager(); } -SwiftPassInvocation *FunctionTest::getSwiftPassInvocation() { - return dependencies->getSwiftPassInvocation(); +SILContext *FunctionTest::getSILContext() { + return dependencies->getSILContext(); } diff --git a/lib/SILOptimizer/PassManager/PassManager.cpp b/lib/SILOptimizer/PassManager/PassManager.cpp index c97a777353772..5a43810450fcd 100644 --- a/lib/SILOptimizer/PassManager/PassManager.cpp +++ b/lib/SILOptimizer/PassManager/PassManager.cpp @@ -27,6 +27,8 @@ #include "swift/SILOptimizer/PassManager/PrettyStackTrace.h" #include "swift/SILOptimizer/PassManager/Transforms.h" #include "swift/SILOptimizer/Utils/OptimizerStatsUtils.h" +#include "swift/SILOptimizer/Utils/SILOptFunctionBuilder.h" +#include "swift/SILOptimizer/Utils/SILSSAUpdater.h" #include "llvm/ADT/DenseMap.h" #include "llvm/ADT/Statistic.h" #include "llvm/ADT/StringSwitch.h" @@ -1427,198 +1429,152 @@ void SILPassManager::viewCallGraph() { // SwiftPassInvocation //===----------------------------------------------------------------------===// -FixedSizeSlab *SwiftPassInvocation::allocSlab(FixedSizeSlab *afterSlab) { - FixedSizeSlab *slab = passManager->getModule()->allocSlab(); - if (afterSlab) { - allocatedSlabs.insert(std::next(afterSlab->getIterator()), *slab); - } else { - allocatedSlabs.push_back(*slab); - } - return slab; +void SwiftPassInvocation::startModulePassRun(SILModuleTransform *transform) { + ASSERT(!this->function && !this->transform && "a pass is already running"); + this->transform = transform; } -FixedSizeSlab *SwiftPassInvocation::freeSlab(FixedSizeSlab *slab) { - FixedSizeSlab *prev = nullptr; - assert(!allocatedSlabs.empty()); - if (&allocatedSlabs.front() != slab) - prev = &*std::prev(slab->getIterator()); - - allocatedSlabs.remove(*slab); - passManager->getModule()->freeSlab(slab); - return prev; +void SwiftPassInvocation::finishedModulePassRun() { + ASSERT(!function && transform && "not running a module pass"); + if (changeNotifications != 0) { + ASSERT((changeNotifications & ~SILContext::NotificationKind::FunctionTables) == 0 + && "a module pass must change the SIL of a function"); + passManager->invalidateFunctionTables(); + changeNotifications = SILContext::NotificationKind::Nothing; + } + transform = nullptr; + verifyEverythingIsCleared(); } -BasicBlockSet *SwiftPassInvocation::allocBlockSet() { - ASSERT(numBlockSetsAllocated < BlockSetCapacity && - "too many BasicBlockSets allocated"); - - auto *storage = (BasicBlockSet *)blockSetStorage + numBlockSetsAllocated; - BasicBlockSet *set = new (storage) BasicBlockSet(function); - aliveBlockSets[numBlockSetsAllocated] = true; - ++numBlockSetsAllocated; - return set; +void SwiftPassInvocation::startFunctionPassRun(SILFunctionTransform *transform) { + ASSERT(!this->function && !this->transform && "a pass is already running"); + this->transform = transform; + this->function = transform->getFunction(); } -void SwiftPassInvocation::freeBlockSet(BasicBlockSet *set) { - int idx = set - (BasicBlockSet *)blockSetStorage; - assert(idx >= 0 && idx < numBlockSetsAllocated); - assert(aliveBlockSets[idx] && "double free of BasicBlockSet"); - aliveBlockSets[idx] = false; +void SwiftPassInvocation::finishedFunctionPassRun() { + ASSERT(function && transform && "not running a function pass"); + ASSERT((changeNotifications & SILContext::NotificationKind::FunctionTables) == 0 + && "a function pass must not change function tables"); + if (changeNotifications != SILContext::NotificationKind::Nothing) { + passManager->invalidateAnalysis(function, (SILAnalysis::InvalidationKind)changeNotifications); + } + changeNotifications = SILContext::NotificationKind::Nothing; - while (numBlockSetsAllocated > 0 && !aliveBlockSets[numBlockSetsAllocated - 1]) { - auto *set = (BasicBlockSet *)blockSetStorage + numBlockSetsAllocated - 1; - set->~BasicBlockSet(); - --numBlockSetsAllocated; + insertedPhisBySSAUpdater.clear(); + if (ssaUpdater) { + delete ssaUpdater; + ssaUpdater = nullptr; } + + function = nullptr; + transform = nullptr; + verifyEverythingIsCleared(); } -NodeSet *SwiftPassInvocation::allocNodeSet() { - ASSERT(numNodeSetsAllocated < NodeSetCapacity && - "too many NodeSets allocated"); +void SwiftPassInvocation::startInstructionPassRun(SILInstruction *inst) { + ASSERT(inst->getFunction() == function && "running instruction pass on wrong function"); +} - auto *storage = (NodeSet *)nodeSetStorage + numNodeSetsAllocated; - NodeSet *set = new (storage) NodeSet(function); - aliveNodeSets[numNodeSetsAllocated] = true; - ++numNodeSetsAllocated; - return set; +void SwiftPassInvocation::finishedInstructionPassRun() { + verifyEverythingIsCleared(); } -void SwiftPassInvocation::freeNodeSet(NodeSet *set) { - int idx = set - (NodeSet *)nodeSetStorage; - assert(idx >= 0 && idx < numNodeSetsAllocated); - assert(aliveNodeSets[idx] && "double free of NodeSet"); - aliveNodeSets[idx] = false; +void SwiftPassInvocation::verifyEverythingIsCleared() { + ASSERT(!needFixStackNesting && "Stack nesting not fixed"); + SILContext::verifyEverythingIsCleared(); +} - while (numNodeSetsAllocated > 0 && !aliveNodeSets[numNodeSetsAllocated - 1]) { - auto *set = (NodeSet *)nodeSetStorage + numNodeSetsAllocated - 1; - set->~NodeSet(); - --numNodeSetsAllocated; +void SwiftPassInvocation::beginVerifyFunction(SILFunction *function) { + if (transform) { + ASSERT(this->function == function); + } else { + ASSERT(!this->function); + this->function = function; } } -OperandSet *SwiftPassInvocation::allocOperandSet() { - ASSERT(numOperandSetsAllocated < OperandSetCapacity && - "too many OperandSets allocated"); +void SwiftPassInvocation::endVerifyFunction() { + ASSERT(function); + if (!transform) { + verifyEverythingIsCleared(); + function = nullptr; + } +} - auto *storage = (OperandSet *)operandSetStorage + numOperandSetsAllocated; - OperandSet *set = new (storage) OperandSet(function); - aliveOperandSets[numOperandSetsAllocated] = true; - ++numOperandSetsAllocated; - return set; +irgen::IRGenModule *SwiftPassInvocation::getIRGenModule() { + return passManager->getIRGenModule(); } -void SwiftPassInvocation::freeOperandSet(OperandSet *set) { - int idx = set - (OperandSet *)operandSetStorage; - assert(idx >= 0 && idx < numOperandSetsAllocated); - assert(aliveOperandSets[idx] && "double free of OperandSet"); - aliveOperandSets[idx] = false; +SwiftPassInvocation::~SwiftPassInvocation() {} - while (numOperandSetsAllocated > 0 && !aliveOperandSets[numOperandSetsAllocated - 1]) { - auto *set = (OperandSet *)operandSetStorage + numOperandSetsAllocated - 1; - set->~OperandSet(); - --numOperandSetsAllocated; - } -} +SILFunction *SwiftPassInvocation:: +createEmptyFunction(StringRef name, + ArrayRef params, + bool hasSelfParam, + SILFunction *fromFn) { + CanSILFunctionType fTy = fromFn->getLoweredFunctionType(); + assert(fromFn->getGenericSignature().isNull() && "generic functions are not supported"); -void SwiftPassInvocation::startModulePassRun(SILModuleTransform *transform) { - assert(!this->function && !this->transform && "a pass is already running"); - this->function = nullptr; - this->transform = transform; -} + auto extInfo = fTy->getExtInfo(); + if (fTy->hasSelfParam() && !hasSelfParam) + extInfo = extInfo.withRepresentation(SILFunctionTypeRepresentation::Thin); -void SwiftPassInvocation::startFunctionPassRun(SILFunctionTransform *transform) { - assert(!this->transform && "a pass is already running"); - this->transform = transform; - beginTransformFunction(transform->getFunction()); -} + CanSILFunctionType newTy = SILFunctionType::get( + /*GenericSignature=*/nullptr, extInfo, fTy->getCoroutineKind(), + fTy->getCalleeConvention(), params, fTy->getYields(), + fTy->getResults(), fTy->getOptionalErrorResult(), + SubstitutionMap(), SubstitutionMap(), + getModule()->getASTContext()); -void SwiftPassInvocation::startInstructionPassRun(SILInstruction *inst) { - assert(inst->getFunction() == function && - "running instruction pass on wrong function"); -} + SILOptFunctionBuilder functionBuilder(*getTransform()); -void SwiftPassInvocation::finishedModulePassRun() { - endPass(); - assert(!function && transform && "not running a pass"); - assert(changeNotifications == SILAnalysis::InvalidationKind::Nothing - && !functionTablesChanged - && "unhandled change notifications at end of module pass"); - transform = nullptr; -} + SILFunction *newF = functionBuilder.createFunction( + fromFn->getLinkage(), name, newTy, nullptr, + fromFn->getLocation(), fromFn->isBare(), fromFn->isTransparent(), + fromFn->getSerializedKind(), IsNotDynamic, IsNotDistributed, + IsNotRuntimeAccessible, fromFn->getEntryCount(), fromFn->isThunk(), + fromFn->getClassSubclassScope(), fromFn->getInlineStrategy(), + fromFn->getEffectsKind(), nullptr, fromFn->getDebugScope()); -void SwiftPassInvocation::finishedFunctionPassRun() { - endPass(); - endTransformFunction(); - assert(allocatedSlabs.empty() && "StackList is leaking slabs"); - transform = nullptr; + return newF; } -void SwiftPassInvocation::finishedInstructionPassRun() { - endPass(); +void SwiftPassInvocation::moveFunctionBody(SILFunction *sourceFn, SILFunction *destFn) { + destFn->moveAllBlocksFromOtherFunction(sourceFn); + getPassManager()->invalidateAnalysis(sourceFn, SILAnalysis::InvalidationKind::Everything); + getPassManager()->invalidateAnalysis(destFn, SILAnalysis::InvalidationKind::Everything); } -irgen::IRGenModule *SwiftPassInvocation::getIRGenModule() { - return passManager->getIRGenModule(); -} +SILFunction *SwiftPassInvocation::lookupStdlibFunction(StringRef name) { + SmallVector results; + getModule()->getASTContext().lookupInSwiftModule(name, results); + if (results.size() != 1) + return nullptr; -void SwiftPassInvocation::endPass() { - insertedPhisBySSAUpdater.clear(); - assert(allocatedSlabs.empty() && "StackList is leaking slabs"); - assert(numBlockSetsAllocated == 0 && "Not all BasicBlockSets deallocated"); - assert(numNodeSetsAllocated == 0 && "Not all NodeSets deallocated"); - assert(numOperandSetsAllocated == 0 && "Not all OperandSets deallocated"); - assert(numClonersAllocated == 0 && "Not all cloners deallocated"); - assert(!needFixStackNesting && "Stack nesting not fixed"); - if (ssaUpdater) { - delete ssaUpdater; - ssaUpdater = nullptr; - } -} + auto *decl = dyn_cast(results.front()); + if (!decl) + return nullptr; -void SwiftPassInvocation::beginTransformFunction(SILFunction *function) { - assert(!this->function && transform && "not running a pass"); - assert(changeNotifications == SILAnalysis::InvalidationKind::Nothing - && !functionTablesChanged - && "change notifications not cleared"); - this->function = function; + SILDeclRef declRef(decl, SILDeclRef::Kind::Func); + SILOptFunctionBuilder funcBuilder(*getTransform()); + return funcBuilder.getOrCreateFunction(SILLocation(decl), declRef, NotForDefinition); } -void SwiftPassInvocation::endTransformFunction() { - assert(function && transform && "not running a pass"); - if (changeNotifications != SILAnalysis::InvalidationKind::Nothing) { - passManager->invalidateAnalysis(function, changeNotifications); - changeNotifications = SILAnalysis::InvalidationKind::Nothing; - } - if (functionTablesChanged) { - passManager->invalidateFunctionTables(); - functionTablesChanged = false; - } - function = nullptr; - assert(numBlockSetsAllocated == 0 && "Not all BasicBlockSets deallocated"); - assert(numNodeSetsAllocated == 0 && "Not all NodeSets deallocated"); - assert(numOperandSetsAllocated == 0 && "Not all OperandSets deallocated"); +void SwiftPassInvocation::initializeSSAUpdater(SILFunction *function, SILType type, ValueOwnershipKind ownership) { + if (!ssaUpdater) + ssaUpdater = new SILSSAUpdater(&insertedPhisBySSAUpdater); + ssaUpdater->initialize(function, type, ownership); } -void SwiftPassInvocation::beginVerifyFunction(SILFunction *function) { - if (transform) { - assert(this->function == function); - } else { - assert(!this->function); - this->function = function; - } +void SwiftPassInvocation::SSAUpdater_addAvailableValue(SILBasicBlock *block, SILValue value) { + ssaUpdater->addAvailableValue(block, value); } -void SwiftPassInvocation::endVerifyFunction() { - assert(function); - if (!transform) { - assert(changeNotifications == SILAnalysis::InvalidationKind::Nothing && - !functionTablesChanged && - "verifyication must not change the SIL of a function"); - assert(numBlockSetsAllocated == 0 && "Not all BasicBlockSets deallocated"); - assert(numNodeSetsAllocated == 0 && "Not all NodeSets deallocated"); - assert(numOperandSetsAllocated == 0 && "Not all OperandSets deallocated"); - function = nullptr; - } +SILValue SwiftPassInvocation::SSAUpdater_getValueAtEndOfBlock(SILBasicBlock *block) { + return ssaUpdater->getValueAtEndOfBlock(block); } -SwiftPassInvocation::~SwiftPassInvocation() {} +SILValue SwiftPassInvocation::SSAUpdater_getValueInMiddleOfBlock(SILBasicBlock *block) { + return ssaUpdater->getValueInMiddleOfBlock(block); +} diff --git a/lib/SILOptimizer/UtilityPasses/TestRunner.cpp b/lib/SILOptimizer/UtilityPasses/TestRunner.cpp index bab10aefe451f..f7e732d13a379 100644 --- a/lib/SILOptimizer/UtilityPasses/TestRunner.cpp +++ b/lib/SILOptimizer/UtilityPasses/TestRunner.cpp @@ -48,7 +48,8 @@ class TestRunner : public SILFunctionTransform { auto *deadEndBlocksAnalysis = pass->getAnalysis(); return deadEndBlocksAnalysis->get(function); } - SwiftPassInvocation *getSwiftPassInvocation() override { + + SILContext *getSILContext() override { return &swiftPassInvocation; } SILPassManager *getPassManager() override { return pass->getPassManager(); } diff --git a/lib/SILOptimizer/Utils/OptimizerBridging.cpp b/lib/SILOptimizer/Utils/OptimizerBridging.cpp index 9e12ed2284192..fbadf6b46f9fb 100644 --- a/lib/SILOptimizer/Utils/OptimizerBridging.cpp +++ b/lib/SILOptimizer/Utils/OptimizerBridging.cpp @@ -16,6 +16,7 @@ #include "swift/SIL/DynamicCasts.h" #include "swift/SIL/OSSALifetimeCompletion.h" #include "swift/SIL/SILCloner.h" +#include "swift/SIL/Test.h" #include "swift/SILOptimizer/Analysis/Analysis.h" #include "swift/SILOptimizer/IPO/ClosureSpecializer.h" #include "swift/SILOptimizer/Utils/CFGOptUtils.h" @@ -48,16 +49,7 @@ llvm::cl::opt DisableSwiftVerification( // PassManager //===----------------------------------------------------------------------===// -static BridgedUtilities::VerifyFunctionFn verifyFunctionFunction; - -void BridgedUtilities::registerVerifier(VerifyFunctionFn verifyFunctionFn) { - verifyFunctionFunction = verifyFunctionFn; -} - void SILPassManager::runSwiftFunctionVerification(SILFunction *f) { - if (!verifyFunctionFunction) - return; - if (f->getModule().getOptions().VerifyNone) return; @@ -69,7 +61,7 @@ void SILPassManager::runSwiftFunctionVerification(SILFunction *f) { } getSwiftPassInvocation()->beginVerifyFunction(f); - verifyFunctionFunction({getSwiftPassInvocation()}, {f}); + BridgedVerifier::runSwiftFunctionVerification(f, getSwiftPassInvocation()); getSwiftPassInvocation()->endVerifyFunction(); } @@ -84,34 +76,6 @@ void SILPassManager::runSwiftModuleVerification() { // OptimizerBridging //===----------------------------------------------------------------------===// -void BridgedChangeNotificationHandler::notifyChanges(Kind changeKind) const { - switch (changeKind) { - case Kind::instructionsChanged: - invocation->notifyChanges(SILAnalysis::InvalidationKind::Instructions); - break; - case Kind::callsChanged: - invocation->notifyChanges(SILAnalysis::InvalidationKind::CallsAndInstructions); - break; - case Kind::branchesChanged: - invocation->notifyChanges(SILAnalysis::InvalidationKind::BranchesAndInstructions); - break; - case Kind::effectsChanged: - invocation->notifyChanges(SILAnalysis::InvalidationKind::Effects); - break; - case Kind::functionTablesChanged: - invocation->notifyFunctionTablesChanged(); - break; - } -} - -BridgedOwnedString BridgedPassContext::getModuleDescription() const { - std::string str; - llvm::raw_string_ostream os(str); - invocation->getPassManager()->getModule()->print(os); - str.pop_back(); // Remove trailing newline. - return BridgedOwnedString(str); -} - bool BridgedPassContext::tryOptimizeApplyOfPartialApply(BridgedInstruction closure) const { auto *pa = closure.getAs(); SILBuilder builder(pa); @@ -355,51 +319,21 @@ BridgedOwnedString BridgedPassContext::mangleWithBoxToStackPromotedArgs( return BridgedOwnedString(mangler.mangle()); } -BridgedGlobalVar BridgedPassContext::createGlobalVariable(BridgedStringRef name, BridgedType type, BridgedLinkage linkage, bool isLet) const { - auto *global = SILGlobalVariable::create( - *invocation->getPassManager()->getModule(), - (swift::SILLinkage)linkage, IsNotSerialized, - name.unbridged(), type.unbridged()); - if (isLet) - global->setLet(true); - return {global}; -} - void BridgedPassContext::fixStackNesting(BridgedFunction function) const { switch (StackNesting::fixNesting(function.getFunction())) { case StackNesting::Changes::None: break; case StackNesting::Changes::Instructions: - invocation->notifyChanges(SILAnalysis::InvalidationKind::Instructions); + invocation->notifyChanges(SILContext::NotificationKind::Instructions); break; case StackNesting::Changes::CFG: - invocation->notifyChanges(SILAnalysis::InvalidationKind::BranchesAndInstructions); + invocation->notifyChanges(SILContext::NotificationKind::Instructions); + invocation->notifyChanges(SILContext::NotificationKind::Branches); break; } invocation->setNeedFixStackNesting(false); } -OptionalBridgedFunction BridgedPassContext::lookupStdlibFunction(BridgedStringRef name) const { - swift::SILModule *mod = invocation->getPassManager()->getModule(); - SmallVector results; - mod->getASTContext().lookupInSwiftModule(name.unbridged(), results); - if (results.size() != 1) - return {nullptr}; - - auto *decl = dyn_cast(results.front()); - if (!decl) - return {nullptr}; - - SILDeclRef declRef(decl, SILDeclRef::Kind::Func); - SILOptFunctionBuilder funcBuilder(*invocation->getTransform()); - return {funcBuilder.getOrCreateFunction(SILLocation(decl), declRef, NotForDefinition)}; -} - -OptionalBridgedFunction BridgedPassContext::lookUpNominalDeinitFunction(BridgedDeclObj nominal) const { - swift::SILModule *mod = invocation->getPassManager()->getModule(); - return {mod->lookUpMoveOnlyDeinitFunction(nominal.getAs())}; -} - bool BridgedPassContext::enableSimplificationFor(BridgedInstruction inst) const { // Fast-path check. if (SimplifyInstructionTest.empty() && !SILPassManager::isAnyPassDisabled()) @@ -420,55 +354,6 @@ bool BridgedPassContext::enableSimplificationFor(BridgedInstruction inst) const return false; } -BridgedFunction BridgedPassContext:: -createEmptyFunction(BridgedStringRef name, - const BridgedParameterInfo * _Nullable bridgedParams, - SwiftInt paramCount, - bool hasSelfParam, - BridgedFunction fromFunc) const { - swift::SILModule *mod = invocation->getPassManager()->getModule(); - SILFunction *fromFn = fromFunc.getFunction(); - - llvm::SmallVector params; - for (unsigned idx = 0; idx < paramCount; ++idx) { - params.push_back(bridgedParams[idx].unbridged()); - } - - CanSILFunctionType fTy = fromFn->getLoweredFunctionType(); - assert(fromFn->getGenericSignature().isNull() && "generic functions are not supported"); - - auto extInfo = fTy->getExtInfo(); - if (fTy->hasSelfParam() && !hasSelfParam) - extInfo = extInfo.withRepresentation(SILFunctionTypeRepresentation::Thin); - - CanSILFunctionType newTy = SILFunctionType::get( - /*GenericSignature=*/nullptr, extInfo, fTy->getCoroutineKind(), - fTy->getCalleeConvention(), params, fTy->getYields(), - fTy->getResults(), fTy->getOptionalErrorResult(), - SubstitutionMap(), SubstitutionMap(), - mod->getASTContext()); - - SILOptFunctionBuilder functionBuilder(*invocation->getTransform()); - - SILFunction *newF = functionBuilder.createFunction( - fromFn->getLinkage(), name.unbridged(), newTy, nullptr, - fromFn->getLocation(), fromFn->isBare(), fromFn->isTransparent(), - fromFn->getSerializedKind(), IsNotDynamic, IsNotDistributed, - IsNotRuntimeAccessible, fromFn->getEntryCount(), fromFn->isThunk(), - fromFn->getClassSubclassScope(), fromFn->getInlineStrategy(), - fromFn->getEffectsKind(), nullptr, fromFn->getDebugScope()); - - return {newF}; -} - -void BridgedPassContext::moveFunctionBody(BridgedFunction sourceFunc, BridgedFunction destFunc) const { - SILFunction *sourceFn = sourceFunc.getFunction(); - SILFunction *destFn = destFunc.getFunction(); - destFn->moveAllBlocksFromOtherFunction(sourceFn); - invocation->getPassManager()->invalidateAnalysis(sourceFn, SILAnalysis::InvalidationKind::Everything); - invocation->getPassManager()->invalidateAnalysis(destFn, SILAnalysis::InvalidationKind::Everything); -} - BridgedFunction BridgedPassContext:: createSpecializedFunctionDeclaration(BridgedStringRef specializedName, const BridgedParameterInfo * _Nullable specializedBridgedParams, @@ -573,81 +458,6 @@ BridgedCalleeAnalysis::CalleeList BridgedCalleeAnalysis::getDestructors(BridgedT return ca->getDestructors(type.unbridged(), isExactType); } -// Need to put ClonerWithFixedLocation into namespace swift to forward reference -// it in OptimizerBridging.h. -namespace swift { - -class ClonerWithFixedLocation : public SILCloner { - friend class SILInstructionVisitor; - friend class SILCloner; - - SILDebugLocation insertLoc; - -public: - ClonerWithFixedLocation(SILGlobalVariable *gVar) - : SILCloner(gVar), - insertLoc(ArtificialUnreachableLocation(), nullptr) {} - - ClonerWithFixedLocation(SILInstruction *insertionPoint) - : SILCloner(*insertionPoint->getFunction()), - insertLoc(insertionPoint->getDebugLocation()) { - Builder.setInsertionPoint(insertionPoint); - } - - SILValue getClonedValue(SILValue v) { - return getMappedValue(v); - } - - void cloneInst(SILInstruction *inst) { - visit(inst); - } - -protected: - - SILLocation remapLocation(SILLocation loc) { - return insertLoc.getLocation(); - } - - const SILDebugScope *remapScope(const SILDebugScope *DS) { - return insertLoc.getScope(); - } -}; - -} // namespace swift - -BridgedCloner::BridgedCloner(BridgedGlobalVar var, BridgedPassContext context) - : cloner(new ClonerWithFixedLocation(var.getGlobal())) { - context.invocation->notifyNewCloner(); -} - -BridgedCloner::BridgedCloner(BridgedInstruction inst, - BridgedPassContext context) - : cloner(new ClonerWithFixedLocation(inst.unbridged())) { - context.invocation->notifyNewCloner(); -} - -void BridgedCloner::destroy(BridgedPassContext context) { - delete cloner; - cloner = nullptr; - context.invocation->notifyClonerDestroyed(); -} - -BridgedValue BridgedCloner::getClonedValue(BridgedValue v) { - return {cloner->getClonedValue(v.getSILValue())}; -} - -bool BridgedCloner::isValueCloned(BridgedValue v) const { - return cloner->isValueCloned(v.getSILValue()); -} - -void BridgedCloner::clone(BridgedInstruction inst) { - cloner->cloneInst(inst.unbridged()); -} - -void BridgedCloner::recordFoldedValue(BridgedValue origValue, BridgedValue mappedValue) { - cloner->recordFoldedValue(origValue.getSILValue(), mappedValue.getSILValue()); -} - namespace swift { class SpecializationCloner: public SILClonerWithScopes { friend class SILInstructionVisitor; @@ -688,11 +498,13 @@ void BridgedBuilder::destroyCapturedArgs(BridgedInstruction partialApply) const } } -void verifierError(BridgedStringRef message, - OptionalBridgedInstruction atInstruction, - OptionalBridgedArgument atArgument) { - Twine msg(message.unbridged()); - verificationFailure(msg, atInstruction.unbridged(), atArgument.unbridged(), /*extraContext=*/nullptr); +//===----------------------------------------------------------------------===// +// Test +//===----------------------------------------------------------------------===// + +void registerFunctionTest(BridgedStringRef name, void *nativeSwiftContext) { + swift::test::FunctionTest::createNativeSwiftFunctionTest( + name.unbridged(), nativeSwiftContext, /*isSILTest=*/ false); } //===----------------------------------------------------------------------===//