Skip to content

Commit 531469f

Browse files
authored
Merge pull request #73864 from Snowy1803/scs-builder-skip-meta
Skip meta instructions for Builder.init with automatic location
2 parents 9a28061 + d39d838 commit 531469f

File tree

6 files changed

+105
-8
lines changed

6 files changed

+105
-8
lines changed

SwiftCompilerSources/Sources/Optimizer/PassManager/Context.swift

Lines changed: 50 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -433,6 +433,34 @@ extension Type {
433433
// Builder initialization
434434
//===----------------------------------------------------------------------===//
435435

436+
private extension Instruction {
437+
/// Returns self, unless self is a meta instruction, in which case the next
438+
/// non-meta instruction is returned. Returns nil if there are no non-meta
439+
/// instructions in the basic block.
440+
var nextNonMetaInstruction: Instruction? {
441+
for inst in InstructionList(first: self) where !(inst is MetaInstruction) {
442+
return inst
443+
}
444+
return nil
445+
}
446+
447+
/// Returns the next interesting location. As it is impossible to set a
448+
/// breakpoint on a meta instruction, those are skipped.
449+
/// However, we don't want to take a location with different inlining
450+
/// information than this instruction, so in that case, we will return the
451+
/// location of the meta instruction. If the meta instruction is the only
452+
/// instruction in the basic block, we also take its location.
453+
var locationOfNextNonMetaInstruction: Location {
454+
let location = self.location
455+
guard !location.isInlined,
456+
let nextLocation = nextNonMetaInstruction?.location,
457+
!nextLocation.isInlined else {
458+
return location
459+
}
460+
return nextLocation
461+
}
462+
}
463+
436464
extension Builder {
437465
/// Creates a builder which inserts _before_ `insPnt`, using a custom `location`.
438466
init(before insPnt: Instruction, location: Location, _ context: some MutatingContext) {
@@ -441,8 +469,23 @@ extension Builder {
441469
context.notifyInstructionChanged, context._bridged.asNotificationHandler())
442470
}
443471

444-
/// Creates a builder which inserts _before_ `insPnt`, using the location of `insPnt`.
472+
/// Creates a builder which inserts before `insPnt`, using `insPnt`'s next
473+
/// non-meta instruction's location.
474+
/// This function should be used when moving code to an unknown insert point,
475+
/// when we want to inherit the location of the closest non-meta instruction.
476+
/// For replacing an existing meta instruction with another, use
477+
/// ``Builder.init(replacing:_:)``.
445478
init(before insPnt: Instruction, _ context: some MutatingContext) {
479+
context.verifyIsTransforming(function: insPnt.parentFunction)
480+
self.init(insertAt: .before(insPnt),
481+
location: insPnt.locationOfNextNonMetaInstruction,
482+
context.notifyInstructionChanged, context._bridged.asNotificationHandler())
483+
}
484+
485+
/// Creates a builder which inserts _before_ `insPnt`, using the exact location of `insPnt`,
486+
/// for the purpose of replacing that meta instruction with an equivalent instruction.
487+
/// This function does not delete `insPnt`.
488+
init(replacing insPnt: MetaInstruction, _ context: some MutatingContext) {
446489
context.verifyIsTransforming(function: insPnt.parentFunction)
447490
self.init(insertAt: .before(insPnt), location: insPnt.location,
448491
context.notifyInstructionChanged, context._bridged.asNotificationHandler())
@@ -460,10 +503,10 @@ extension Builder {
460503
}
461504
}
462505

463-
/// Creates a builder which inserts _after_ `insPnt`, using the location of `insPnt`.
506+
/// Creates a builder which inserts _after_ `insPnt`, using `insPnt`'s next
507+
/// non-meta instruction's location.
464508
init(after insPnt: Instruction, _ context: some MutatingContext) {
465-
context.verifyIsTransforming(function: insPnt.parentFunction)
466-
self.init(after: insPnt, location: insPnt.location, context)
509+
self.init(after: insPnt, location: insPnt.locationOfNextNonMetaInstruction, context)
467510
}
468511

469512
/// Creates a builder which inserts at the end of `block`, using a custom `location`.
@@ -482,11 +525,12 @@ extension Builder {
482525
}
483526

484527
/// Creates a builder which inserts at the begin of `block`, using the location of the first
485-
/// instruction of `block`.
528+
/// non-meta instruction of `block`.
486529
init(atBeginOf block: BasicBlock, _ context: some MutatingContext) {
487530
context.verifyIsTransforming(function: block.parentFunction)
488531
let firstInst = block.instructions.first!
489-
self.init(insertAt: .before(firstInst), location: firstInst.location,
532+
self.init(insertAt: .before(firstInst),
533+
location: firstInst.locationOfNextNonMetaInstruction,
490534
context.notifyInstructionChanged, context._bridged.asNotificationHandler())
491535
}
492536

SwiftCompilerSources/Sources/SIL/Instruction.swift

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -418,7 +418,16 @@ public protocol DebugVariableInstruction : VarDeclInstruction {
418418
var debugVariable: DebugVariable { get }
419419
}
420420

421-
final public class DebugValueInst : Instruction, UnaryInstruction, DebugVariableInstruction {
421+
/// A meta instruction is an instruction whose location is not interesting as
422+
/// it is impossible to set a breakpoint on it.
423+
/// That could be because the instruction does not generate code (such as
424+
/// `debug_value`), or because the generated code would be in the prologue
425+
/// (`alloc_stack`).
426+
/// When we are moving code onto an unknown instruction (such as the start of a
427+
/// basic block), we want to ignore any meta instruction that might be there.
428+
public protocol MetaInstruction: Instruction {}
429+
430+
final public class DebugValueInst : Instruction, UnaryInstruction, DebugVariableInstruction, MetaInstruction {
422431
public var varDecl: VarDecl? {
423432
VarDecl(bridged: bridged.DebugValue_getDecl())
424433
}
@@ -1127,7 +1136,7 @@ final public class InitBlockStorageHeaderInst: SingleValueInstruction {}
11271136

11281137
public protocol Allocation : SingleValueInstruction { }
11291138

1130-
final public class AllocStackInst : SingleValueInstruction, Allocation, DebugVariableInstruction {
1139+
final public class AllocStackInst : SingleValueInstruction, Allocation, DebugVariableInstruction, MetaInstruction {
11311140
public var hasDynamicLifetime: Bool { bridged.AllocStackInst_hasDynamicLifetime() }
11321141

11331142
public var varDecl: VarDecl? {

SwiftCompilerSources/Sources/SIL/Location.swift

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@ public struct Location: Equatable, CustomStringConvertible {
3030

3131
public var hasValidLineNumber: Bool { bridged.hasValidLineNumber() }
3232
public var isAutoGenerated: Bool { bridged.isAutoGenerated() }
33+
public var isInlined: Bool { bridged.isInlined() }
3334

3435
public var isDebugSteppable: Bool { hasValidLineNumber && !isAutoGenerated }
3536

include/swift/SIL/SILBridging.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -534,6 +534,7 @@ struct BridgedLocation {
534534
SWIFT_IMPORT_UNSAFE BRIDGED_INLINE BridgedLocation getAutogeneratedLocation() const;
535535
BRIDGED_INLINE bool hasValidLineNumber() const;
536536
BRIDGED_INLINE bool isAutoGenerated() const;
537+
BRIDGED_INLINE bool isInlined() const;
537538
BRIDGED_INLINE bool isEqualTo(BridgedLocation rhs) const;
538539
SWIFT_IMPORT_UNSAFE BRIDGED_INLINE BridgedSourceLoc getSourceLocation() const;
539540
BRIDGED_INLINE bool hasSameSourceLocation(BridgedLocation rhs) const;

include/swift/SIL/SILBridgingImpl.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -566,6 +566,9 @@ bool BridgedLocation::hasValidLineNumber() const {
566566
bool BridgedLocation::isAutoGenerated() const {
567567
return getLoc().isAutoGenerated();
568568
}
569+
bool BridgedLocation::isInlined() const {
570+
return getLoc().getScope()->InlinedCallSite;
571+
}
569572
bool BridgedLocation::isEqualTo(BridgedLocation rhs) const {
570573
return getLoc().isEqualTo(rhs.getLoc());
571574
}
Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
// RUN: %target-sil-opt -enable-sil-verify-all %s -simplification -simplify-instruction=checked_cast_br -sil-print-debuginfo | %FileCheck %s
2+
3+
// REQUIRES: swift_in_compiler
4+
5+
import Swift
6+
import Builtin
7+
8+
protocol P : AnyObject {}
9+
class B : P {}
10+
class X : B {}
11+
12+
// CHECK-LABEL: sil [ossa] @test_ossa :
13+
// CHECK: %0 = alloc_ref
14+
// CHECK-NEXT: checked_cast_br AnyObject in %0 : $X
15+
// CHECK: bb2([[A:%.*]] : @owned $X):
16+
// CHECK-NEXT: [[U:%.*]] = upcast [[A]] : $X to $B, loc "takethis":1:1
17+
// CHECK-NEXT: [[E:%.*]] = init_existential_ref [[U]] {{.+}}, loc "takethis":1:1
18+
// CHECK-NEXT: debug_value [[E]] : $AnyObject, let, name "me", loc "ignore-this-meta-inst":1:1
19+
// CHECK-NEXT: destroy_value [[E]] : $AnyObject, loc "takethis":1:1
20+
// CHECK: } // end sil function 'test_ossa'
21+
sil [ossa] @test_ossa : $@convention(thin) () -> @owned X {
22+
bb0:
23+
%0 = alloc_ref $X
24+
%1 = upcast %0 : $X to $B
25+
%2 = init_existential_ref %1 : $B : $B, $AnyObject
26+
debug_value %2 : $AnyObject, name "x"
27+
checked_cast_br AnyObject in %2 : $AnyObject to X, bb1, bb2
28+
29+
bb1(%5 : @owned $X):
30+
return %5 : $X
31+
32+
bb2(%7 : @owned $AnyObject):
33+
debug_value %7 : $AnyObject, let, name "me", loc "ignore-this-meta-inst":1:1
34+
destroy_value %7: $AnyObject, loc "takethis":1:1
35+
unreachable
36+
}
37+
38+
sil_vtable X {
39+
}

0 commit comments

Comments
 (0)