SwiftCompilerSources: move SIL-related Context APIs from Optimizer to the SIL module

This commit is contained in:
Erik Eckstein
2025-07-28 10:38:45 +02:00
parent 319f49ad9f
commit 41a6b8e257
20 changed files with 361 additions and 430 deletions

View File

@@ -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

View File

@@ -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)
}
}
}

View File

@@ -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
}
}

View File

@@ -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

View File

@@ -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

View File

@@ -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)
}
}

View File

@@ -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)
}
}

View File

@@ -113,7 +113,7 @@ private struct StackProtectionOptimization {
process(instruction: inst, in: function, mustFixStackNesting: &mustFixStackNesting, context)
}
if mustFixStackNesting {
function.fixStackNesting(context)
context.fixStackNesting(in: function)
}
}

View File

@@ -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)
}
}

View File

@@ -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 }) {

View File

@@ -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 {

View File

@@ -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.

View File

@@ -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

View File

@@ -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)

View File

@@ -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 {

View File

@@ -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.

View File

@@ -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<ArgumentArray, FunctionArgument> {
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)
}
}

View File

@@ -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..<numTailTypes]
@@ -1416,6 +1506,12 @@ public class AllocRefInstBase : SingleValueInstruction, Allocation {
final public class AllocRefInst : AllocRefInstBase {
public var isBare: Bool { bridged.AllocRefInst_isBare() }
public func setIsBare(_ context: some MutatingContext) {
context.notifyInstructionsChanged()
bridged.AllocRefInst_setIsBare()
context.notifyInstructionChanged(self)
}
}
final public class AllocRefDynamicInst : AllocRefInstBase {
@@ -1530,6 +1626,11 @@ final public class BeginAccessInst : SingleValueInstruction, UnaryInstruction {
public var accessKind: AccessKind {
AccessKind(rawValue: bridged.BeginAccessInst_getAccessKind())!
}
public func set(accessKind: BeginAccessInst.AccessKind, context: some MutatingContext) {
context.notifyInstructionsChanged()
bridged.BeginAccess_setAccessKind(accessKind.rawValue)
context.notifyInstructionChanged(self)
}
public var isStatic: Bool { bridged.BeginAccessInst_isStatic() }
public var isUnsafe: Bool { bridged.BeginAccessInst_isUnsafe() }
@@ -1691,6 +1792,11 @@ public class TermInst : Instruction {
}
public var isFunctionExiting: Bool { false }
public final func replaceBranchTarget(from fromBlock: BasicBlock, to toBlock: BasicBlock, _ context: some MutatingContext) {
context.notifyBranchesChanged()
bridged.TermInst_replaceBranchTarget(fromBlock.bridged, toBlock.bridged)
}
}
final public class UnreachableInst : TermInst {

View File

@@ -27,6 +27,10 @@ public struct Operand : CustomStringConvertible, NoReflectionChildren, Equatable
public var value: Value { bridged.getValue().value }
public func set(to value: Value, _ context: some MutatingContext) {
instruction.setOperand(at: index, to: value, context)
}
public static func ==(lhs: Operand, rhs: Operand) -> 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<I: Instruction>(ofType: I.Type) -> LazyMapSequence<LazyFilterSequence<Self>, 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 {

View File

@@ -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 {