Skip to content

Commit f5fc178

Browse files
committed
[NFC] SwiftCompilerSources: Add VariableScopeInstruction utility
To diagnose dependence on trivial variables.
1 parent 74b235e commit f5fc178

File tree

3 files changed

+85
-27
lines changed

3 files changed

+85
-27
lines changed

SwiftCompilerSources/Sources/Optimizer/FunctionPasses/LifetimeDependenceDiagnostics.swift

Lines changed: 0 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -250,22 +250,6 @@ private struct DiagnoseDependence {
250250
}
251251
}
252252

253-
private extension Instruction {
254-
func findVarDecl() -> VarDecl? {
255-
if let varDeclInst = self as? VarDeclInstruction {
256-
return varDeclInst.varDecl
257-
}
258-
for result in results {
259-
for use in result.uses {
260-
if let debugVal = use.instruction as? DebugValueInst {
261-
return debugVal.varDecl
262-
}
263-
}
264-
}
265-
return nil
266-
}
267-
}
268-
269253
// Identify a best-effort variable declaration based on a defining SIL
270254
// value or any lifetime dependent use of that SIL value.
271255
private struct LifetimeVariable {

SwiftCompilerSources/Sources/Optimizer/Utilities/LifetimeDependenceUtils.swift

Lines changed: 3 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,7 @@
5252
//
5353
//===----------------------------------------------------------------------===//
5454

55+
import AST
5556
import SIL
5657

5758
private let verbose = false
@@ -593,17 +594,8 @@ struct VariableIntroducerUseDefWalker : LifetimeDependenceUseDefWalker {
593594
}
594595

595596
mutating func walkUp(value: Value, _ owner: Value?) -> WalkResult {
596-
switch value.definingInstruction {
597-
case let moveInst as MoveValueInst:
598-
if moveInst.isFromVarDecl {
599-
return introducer(moveInst, owner)
600-
}
601-
case let borrow as BeginBorrowInst:
602-
if borrow.isFromVarDecl {
603-
return introducer(borrow, owner)
604-
}
605-
default:
606-
break
597+
if let inst = value.definingInstruction, VariableScopeInstruction(inst) != nil {
598+
return introducer(value, owner)
607599
}
608600
return walkUpDefault(dependent: value, owner: owner)
609601
}

SwiftCompilerSources/Sources/SIL/Instruction.swift

Lines changed: 82 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -401,6 +401,88 @@ public protocol VarDeclInstruction {
401401
var varDecl: VarDecl? { get }
402402
}
403403

404+
/// A scoped instruction whose single result introduces a variable scope.
405+
///
406+
/// The scope-ending uses represent the end of the variable scope. This allows trivial 'let' variables to be treated
407+
/// like a value with ownership. 'var' variables are primarily represented as addressable allocations via alloc_box or
408+
/// alloc_stack, but may have redundant VariableScopeInstructions.
409+
public enum VariableScopeInstruction {
410+
case beginBorrow(BeginBorrowInst)
411+
case moveValue(MoveValueInst)
412+
413+
public init?(_ inst: Instruction?) {
414+
switch inst {
415+
case let bbi as BeginBorrowInst:
416+
guard bbi.isFromVarDecl else {
417+
return nil
418+
}
419+
self = .beginBorrow(bbi)
420+
case let mvi as MoveValueInst:
421+
guard mvi.isFromVarDecl else {
422+
return nil
423+
}
424+
self = .moveValue(mvi)
425+
default:
426+
return nil
427+
}
428+
}
429+
430+
public var instruction: Instruction {
431+
switch self {
432+
case let .beginBorrow(bbi):
433+
return bbi
434+
case let .moveValue(mvi):
435+
return mvi
436+
}
437+
}
438+
439+
public var scopeBegin: Value {
440+
instruction as! SingleValueInstruction
441+
}
442+
443+
public var endOperands: LazyFilterSequence<UseList> {
444+
return scopeBegin.uses.endingLifetime
445+
}
446+
447+
// TODO: with SIL verification, we might be able to make varDecl non-Optional.
448+
public var varDecl: VarDecl? {
449+
if let debugVarDecl = instruction.debugVarDecl {
450+
return debugVarDecl
451+
}
452+
// SILGen may produce double var_decl instructions for the same variable:
453+
// %box = alloc_box [var_decl] "x"
454+
// begin_borrow %box [var_decl]
455+
//
456+
// Assume that, if the begin_borrow or move_value does not have its own debug_value, then it must actually be
457+
// associated with its operand's var_decl.
458+
return instruction.operands[0].value.definingInstruction?.findVarDecl()
459+
}
460+
}
461+
462+
extension Instruction {
463+
/// Find a variable declaration assoicated with this instruction.
464+
public func findVarDecl() -> VarDecl? {
465+
if let varDeclInst = self as? VarDeclInstruction {
466+
return varDeclInst.varDecl
467+
}
468+
if let varScopeInst = VariableScopeInstruction(self) {
469+
return varScopeInst.varDecl
470+
}
471+
return debugVarDecl
472+
}
473+
474+
var debugVarDecl: VarDecl? {
475+
for result in results {
476+
for use in result.uses {
477+
if let debugVal = use.instruction as? DebugValueInst {
478+
return debugVal.varDecl
479+
}
480+
}
481+
}
482+
return nil
483+
}
484+
}
485+
404486
public protocol DebugVariableInstruction : VarDeclInstruction {
405487
typealias DebugVariable = OptionalBridgedSILDebugVariable
406488

0 commit comments

Comments
 (0)