From 41a6b8e257b543753ab7d1949db360e2668f802c Mon Sep 17 00:00:00 2001 From: Erik Eckstein Date: Mon, 28 Jul 2025 10:38:45 +0200 Subject: [PATCH] SwiftCompilerSources: move SIL-related Context APIs from Optimizer to the SIL module --- .../FunctionPasses/AllocBoxToStack.swift | 2 +- .../ClosureSpecialization.swift | 4 +- .../FunctionPasses/ComputeEscapeEffects.swift | 2 +- .../FunctionPasses/ComputeSideEffects.swift | 2 +- .../FunctionPasses/SimplificationPasses.swift | 2 +- .../FunctionPasses/StackPromotion.swift | 2 +- .../SimplifyBuiltin.swift | 4 +- .../ModulePasses/StackProtection.swift | 2 +- .../Optimizer/PassManager/Context.swift | 388 +----------------- .../Optimizer/Utilities/OptUtils.swift | 18 - .../Sources/SIL/Argument.swift | 15 + .../Sources/SIL/BasicBlock.swift | 98 ++++- .../Sources/SIL/Builder.swift | 83 +++- .../Sources/SIL/Context.swift | 4 + .../Sources/SIL/DeclRef.swift | 6 + .../Sources/SIL/ForwardingInstruction.swift | 7 +- .../Sources/SIL/Function.swift | 26 +- .../Sources/SIL/Instruction.swift | 106 +++++ .../Sources/SIL/Operand.swift | 16 + SwiftCompilerSources/Sources/SIL/Value.swift | 4 + 20 files changed, 361 insertions(+), 430 deletions(-) diff --git a/SwiftCompilerSources/Sources/Optimizer/FunctionPasses/AllocBoxToStack.swift b/SwiftCompilerSources/Sources/Optimizer/FunctionPasses/AllocBoxToStack.swift index 416350b9b8d..6856e64c23f 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 ff2458dfa70..8559e836568 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 e452967c276..3b2ab2c5e24 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 ce60db6ba19..427c599a1fd 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 678024ac9c9..07b0cac69f0 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 2d0fe05b96f..7d522eade4b 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 b7fb3a4244b..dca616d2e2e 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 3c82c874bf3..ba24846817d 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/Context.swift b/SwiftCompilerSources/Sources/Optimizer/PassManager/Context.swift index 602619a6e7f..640e36d529f 100644 --- a/SwiftCompilerSources/Sources/Optimizer/PassManager/Context.swift +++ b/SwiftCompilerSources/Sources/Optimizer/PassManager/Context.swift @@ -193,15 +193,6 @@ struct FunctionPassContext : MutatingContext { } } - func modifyEffects(in function: Function, _ body: (inout FunctionEffects) -> ()) { - notifyEffectsChanged() - function._modifyEffects(body) - } - - fileprivate func notifyEffectsChanged() { - _bridged.notifyChanges(.Effects) - } - func eliminateDeadAllocations(in function: Function) -> Bool { if bridgedPassContext.eliminateDeadAllocations(function.bridged) { notifyInstructionsChanged() @@ -289,14 +280,24 @@ struct FunctionPassContext : MutatingContext { notifyInstructionsChanged() } } + + func fixStackNesting(in function: Function) { + bridgedPassContext.fixStackNesting(function.bridged) + } } struct SimplifyContext : MutatingContext { let _bridged: BridgedContext let notifyInstructionChanged: (Instruction) -> () let preserveDebugInfo: Bool + + func constantFold(builtin: BuiltinInst) -> Value? { + bridgedPassContext.constantFoldBuiltin(builtin.bridged).value + } } +// Those Type APIs get information from IRGenModule, so they are formally not part of SIL and +// therefore need to be defined here, in the Optimizer module. extension Type { func getStaticSize(context: SimplifyContext) -> Int? { let v = context.bridgedPassContext.getStaticSize(self.bridged) @@ -313,372 +314,3 @@ extension Type { 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) - } - - /// 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) - } - - /// 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) - } - - /// 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) - } - - /// 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) - } - - /// 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) - } - - /// 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) - } - - /// 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) - } - - init(staticInitializerOf global: GlobalVariable, _ context: some MutatingContext) { - self.init(insertAt: .staticInitializer(global), - location: Location.artificialUnreachableLocation, { _ in }, context._bridged) - } -} - -//===----------------------------------------------------------------------===// -// 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) { - BridgedContext.moveInstructionBefore(bridged, otherInstruction.bridged) - context.notifyInstructionsChanged() - } -} - -extension BuiltinInst { - func constantFold(_ context: SimplifyContext) -> Value? { - context.bridgedPassContext.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.bridgedPassContext.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/Utilities/OptUtils.swift b/SwiftCompilerSources/Sources/Optimizer/Utilities/OptUtils.swift index fade32f4d94..90c94ca4ba1 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 }) { diff --git a/SwiftCompilerSources/Sources/SIL/Argument.swift b/SwiftCompilerSources/Sources/SIL/Argument.swift index bd7c229bbde..1cf9886a763 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 3d9613c085a..dcf5bb68474 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 0699a8f9670..59f4cd86263 100644 --- a/SwiftCompilerSources/Sources/SIL/Builder.swift +++ b/SwiftCompilerSources/Sources/SIL/Builder.swift @@ -29,6 +29,87 @@ public struct Builder { 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 { @@ -70,7 +151,7 @@ public struct Builder { return instruction } - public init(insertAt: InsertionPoint, location: Location, + private init(insertAt: InsertionPoint, location: Location, _ notifyNewInstruction: @escaping (Instruction) -> (), _ notificationHandler: BridgedContext) { self.insertionPoint = insertAt diff --git a/SwiftCompilerSources/Sources/SIL/Context.swift b/SwiftCompilerSources/Sources/SIL/Context.swift index 272b1c76dd7..71099683384 100644 --- a/SwiftCompilerSources/Sources/SIL/Context.swift +++ b/SwiftCompilerSources/Sources/SIL/Context.swift @@ -110,6 +110,10 @@ extension MutatingContext { _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) diff --git a/SwiftCompilerSources/Sources/SIL/DeclRef.swift b/SwiftCompilerSources/Sources/SIL/DeclRef.swift index 3793441e3b2..a41660a57cc 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 174c0e30be8..276bef4a9ff 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 d61fd310be6..bb28fd1aab3 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 7383e91ecae..31a8c89c56d 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/Value.swift b/SwiftCompilerSources/Sources/SIL/Value.swift index c0397df172d..a346cb621ba 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 {