Skip to content

Optimizer: add a new destroy-hoisting optimization #78059

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 5 commits into from
Dec 11, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -40,9 +40,6 @@ import SIL
/// destruct this data structure, e.g. in a `defer {}` block.
struct InstructionRange : CustomStringConvertible, NoReflectionChildren {

/// The dominating begin instruction.
let begin: Instruction

/// The underlying block range.
private(set) var blockRange: BasicBlockRange

Expand All @@ -52,36 +49,37 @@ struct InstructionRange : CustomStringConvertible, NoReflectionChildren {
private var inExclusiveRange: InstructionSet

init(begin beginInst: Instruction, _ context: some Context) {
self.begin = beginInst
self.blockRange = BasicBlockRange(begin: beginInst.parentBlock, context)
self.insertedInsts = InstructionSet(context)
self.inExclusiveRange = InstructionSet(context)
self = InstructionRange(beginBlock: beginInst.parentBlock, context)
self.inExclusiveRange.insert(beginInst)
}

init(for value: Value, _ context: some Context) {
self = InstructionRange(begin: InstructionRange.beginningInstruction(for: value), context)
if let inst = value.definingInstruction {
self = InstructionRange(begin: inst, context)
} else if let arg = value as? Argument {
self = InstructionRange(beginBlock: arg.parentBlock, context)
} else {
fatalError("cannot build an instruction range for \(value)")
}
}

static func beginningInstruction(for value: Value) -> Instruction {
if let def = value.definingInstructionOrTerminator {
return def
}
assert(Phi(value) != nil || value is FunctionArgument)
return value.parentBlock.instructions.first!
private init(beginBlock: BasicBlock, _ context: some Context) {
self.blockRange = BasicBlockRange(begin: beginBlock, context)
self.insertedInsts = InstructionSet(context)
self.inExclusiveRange = InstructionSet(context)
}

/// Insert a potential end instruction.
mutating func insert(_ inst: Instruction) {
insertedInsts.insert(inst)
insertIntoRange(instructions: ReverseInstructionList(first: inst.previous))
blockRange.insert(inst.parentBlock)
if inst.parentBlock != begin.parentBlock {
if inst.parentBlock != blockRange.begin {
// The first time an instruction is inserted in another block than the begin-block we need to insert
// instructions from the begin instruction to the end of the begin block.
// For subsequent insertions this is a no-op: `insertIntoRange` will return immediately because those
// instruction are already inserted.
insertIntoRange(instructions: begin.parentBlock.instructions.reversed())
insertIntoRange(instructions: blockRange.begin.instructions.reversed())
}
}

Expand All @@ -98,22 +96,14 @@ struct InstructionRange : CustomStringConvertible, NoReflectionChildren {
return true
}
let block = inst.parentBlock
return block != begin.parentBlock && blockRange.contains(block)
return block != blockRange.begin && blockRange.contains(block)
}

/// Returns true if the inclusive range contains `inst`.
func inclusiveRangeContains (_ inst: Instruction) -> Bool {
contains(inst) || insertedInsts.contains(inst)
}

/// Returns true if the range is valid and that's iff the begin instruction
/// dominates all instructions of the range.
var isValid: Bool {
blockRange.isValid &&
// Check if there are any inserted instructions before the begin instruction in its block.
!ReverseInstructionList(first: begin).dropFirst().contains { insertedInsts.contains($0) }
}

/// Returns the end instructions.
///
/// Warning: this returns `begin` if no instructions were inserted.
Expand Down Expand Up @@ -155,6 +145,10 @@ struct InstructionRange : CustomStringConvertible, NoReflectionChildren {
}
}

var begin: Instruction? {
blockRange.begin.instructions.first(where: inExclusiveRange.contains)
}

private mutating func insertIntoRange(instructions: ReverseInstructionList) {
for inst in instructions {
if !inExclusiveRange.insert(inst) {
Expand All @@ -164,9 +158,9 @@ struct InstructionRange : CustomStringConvertible, NoReflectionChildren {
}

var description: String {
return (isValid ? "" : "<invalid>\n") +
return (blockRange.isValid ? "" : "<invalid>\n") +
"""
begin: \(begin)
begin: \(begin?.description ?? blockRange.begin.name)
ends: \(ends.map { $0.description }.joined(separator: "\n "))
exits: \(exits.map { $0.description }.joined(separator: "\n "))
interiors:\(interiors.map { $0.description }.joined(separator: "\n "))
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ swift_compiler_sources(Optimizer
ComputeSideEffects.swift
DeadStoreElimination.swift
DeinitDevirtualizer.swift
DestroyHoisting.swift
InitializeStaticGlobals.swift
LetPropertyLowering.swift
LifetimeDependenceDiagnostics.swift
Expand Down
Loading