Skip to content

Commit 9a2e245

Browse files
Merge pull request #73504 from Snowy1803/rdar127348128
[DebugInfo] Fix verifier crash for complex switch
2 parents c6745e6 + 95d2479 commit 9a2e245

File tree

10 files changed

+111
-48
lines changed

10 files changed

+111
-48
lines changed

include/swift/SIL/SILBuilder.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -423,6 +423,9 @@ class SILBuilder {
423423
#else
424424
(void)skipVarDeclAssert;
425425
#endif
426+
// Don't apply location overrides on variables.
427+
if (Var && !Var->Loc)
428+
Var->Loc = Loc;
426429
return insert(AllocStackInst::create(
427430
getSILDebugLocation(Loc, true), elementType, getFunction(),
428431
substituteAnonymousArgs(Name, Var, Loc), dynamic, isLexical,

include/swift/SIL/SILInstruction.h

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2083,6 +2083,13 @@ class AllocStackInst final
20832083
/// VarDecl.
20842084
void setIsFromVarDecl() { sharedUInt8().AllocStackInst.fromVarDecl = true; }
20852085

2086+
/// Return the SILLocation for the debug variable.
2087+
SILLocation getVarLoc() const {
2088+
if (hasAuxDebugLocation())
2089+
return *getTrailingObjects<SILLocation>();
2090+
return getLoc();
2091+
}
2092+
20862093
/// Return the debug variable information attached to this instruction.
20872094
std::optional<SILDebugVariable> getVarInfo() const {
20882095
// If we used to have debug info attached but our debug info is now
@@ -5374,6 +5381,13 @@ class DebugValueInst final
53745381
/// or null if we don't have one.
53755382
VarDecl *getDecl() const;
53765383

5384+
/// Return the SILLocation for the debug variable.
5385+
SILLocation getVarLoc() const {
5386+
if (hasAuxDebugLocation())
5387+
return *getTrailingObjects<SILLocation>();
5388+
return getLoc();
5389+
}
5390+
53775391
/// Return the debug variable information attached to this instruction.
53785392
std::optional<SILDebugVariable> getVarInfo() const {
53795393
std::optional<SILType> AuxVarType;

lib/SIL/IR/SILInstructions.cpp

Lines changed: 22 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -266,6 +266,15 @@ AllocStackInst *AllocStackInst::create(SILDebugLocation Loc,
266266
IsLexical_t isLexical,
267267
IsFromVarDecl_t isFromVarDecl,
268268
UsesMoveableValueDebugInfo_t wasMoved) {
269+
// Don't store the same information twice.
270+
if (Var) {
271+
if (Var->Loc == Loc.getLocation())
272+
Var->Loc = {};
273+
if (Var->Scope == Loc.getScope())
274+
Var->Scope = nullptr;
275+
if (Var->Type == elementType)
276+
Var->Type = {};
277+
}
269278
SmallVector<SILValue, 8> TypeDependentOperands;
270279
collectTypeDependentOperands(TypeDependentOperands, F,
271280
elementType.getASTType());
@@ -277,6 +286,9 @@ AllocStackInst *AllocStackInst::create(SILDebugLocation Loc,
277286
}
278287

279288
VarDecl *AllocationInst::getDecl() const {
289+
if (auto ASI = dyn_cast<AllocStackInst>(this)) {
290+
return ASI->getVarLoc().getAsASTNode<VarDecl>();
291+
}
280292
return getLoc().getAsASTNode<VarDecl>();
281293
}
282294

@@ -460,6 +472,13 @@ DebugValueInst *DebugValueInst::create(SILDebugLocation DebugLoc,
460472
SILDebugVariable Var, bool poisonRefs,
461473
UsesMoveableValueDebugInfo_t wasMoved,
462474
bool trace) {
475+
// Don't store the same information twice.
476+
if (Var.Loc == DebugLoc.getLocation())
477+
Var.Loc = {};
478+
if (Var.Scope == DebugLoc.getScope())
479+
Var.Scope = nullptr;
480+
if (Var.Type == Operand->getType().getObjectType())
481+
Var.Type = {};
463482
void *buf = allocateDebugVarCarryingInst<DebugValueInst>(M, Var);
464483
return ::new (buf)
465484
DebugValueInst(DebugLoc, Operand, Var, poisonRefs, wasMoved, trace);
@@ -474,9 +493,8 @@ DebugValueInst::createAddr(SILDebugLocation DebugLoc, SILValue Operand,
474493
if (!isa<AllocStackInst>(Operand))
475494
Var.DIExpr.prependElements(
476495
{SILDIExprElement::createOperator(SILDIExprOperator::Dereference)});
477-
void *buf = allocateDebugVarCarryingInst<DebugValueInst>(M, Var);
478-
return ::new (buf) DebugValueInst(DebugLoc, Operand, Var,
479-
/*poisonRefs=*/false, wasMoved, trace);
496+
return DebugValueInst::create(DebugLoc, Operand, M, Var,
497+
/*poisonRefs=*/false, wasMoved, trace);
480498
}
481499

482500
bool DebugValueInst::exprStartsWithDeref() const {
@@ -490,7 +508,7 @@ bool DebugValueInst::exprStartsWithDeref() const {
490508
}
491509

492510
VarDecl *DebugValueInst::getDecl() const {
493-
return getLoc().getAsASTNode<VarDecl>();
511+
return getVarLoc().getAsASTNode<VarDecl>();
494512
}
495513

496514
VarDecl *SILDebugVariable::getDecl() const {

test/DebugInfo/case-match-vars.swift

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
// RUN: %empty-directory(%t)
2+
// RUN: %{python} %utils/split_file.py -o %t %s
3+
4+
// RUN: %target-swift-frontend -module-name a -parse-as-library -emit-ir -g %t/Seq.swift %t/A.swift | %FileCheck %s
5+
6+
// This code used to trigger the verifier.
7+
// https://github.com/apple/swift/issues/73338
8+
9+
// BEGIN Seq.swift
10+
struct A<Element: Equatable>: ExpressibleByArrayLiteral, Equatable {
11+
var base: Element?
12+
init(arrayLiteral elements: Element...) {}
13+
}
14+
struct B<Element: Equatable>: ExpressibleByArrayLiteral, Equatable {
15+
var first: Element?
16+
init(arrayLiteral elements: Element...) {}
17+
}
18+
19+
// BEGIN A.swift
20+
enum E<T: P> {
21+
case a(A<T.ID>)
22+
case b(B<T.ID>)
23+
case c
24+
25+
static func ==(lhs: Self, rhs: Self) -> Bool {
26+
switch (lhs, rhs) {
27+
case (.a([]), .c), (.c, .a([])),
28+
(.b([]), .c), (.c, .b([])):
29+
return true
30+
default:
31+
return false
32+
}
33+
}
34+
}
35+
public protocol P {
36+
associatedtype ID: Equatable
37+
}
38+
39+
// The [] expressions should be available in the debugger
40+
41+
// CHECK: !DILocalVariable(name: "$_0", {{.+}} line: 9
42+
// CHECK: !DILocalVariable(name: "$_1", {{.+}} line: 9
43+
// CHECK: !DILocalVariable(name: "$_2", {{.+}} line: 8
44+
// CHECK: !DILocalVariable(name: "$_3", {{.+}} line: 8
45+

test/DebugInfo/copyforward.sil

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ bb0(%0 : $*Optional<Element>, %1 : $*CollectionOfOne<Element>.Iterator):
1717
%3 = alloc_stack [lexical] [var_decl] $Optional<Element>, let, name "result", loc "backward.swift":67:9, scope 2
1818
%4 = struct_element_addr %1 : $*CollectionOfOne<Element>.Iterator, #CollectionOfOne.Iterator._elements, loc "backward.swift":67:18, scope 1
1919

20-
// CHECK: debug_value %{{[0-9]+}} : $*Optional<Element>, let, (name "result", loc "backward.swift":67:9, scope 2), expr op_deref, loc "backward.swift":67:18, scope 2
20+
// CHECK: debug_value %{{[0-9]+}} : $*Optional<Element>, let, (name "result", loc "backward.swift":67:9), expr op_deref, loc "backward.swift":67:18, scope 2
2121

2222
copy_addr %4 to [init] %3 : $*Optional<Element>, loc "backward.swift":67:18, scope 1
2323
%6 = alloc_stack $Optional<Element>, loc "backward.swift":68:17, scope 2

test/DebugInfo/debug_info_expression.sil

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ bb0:
2525
%3 = struct_element_addr %2 : $*MyStruct, #MyStruct.x, loc "file.swift":9:17, scope 1
2626
// CHECK: %[[FIELD_X:.*]] = getelementptr {{.*}} %[[MY_STRUCT]]
2727
// CHECK-SIL: debug_value %{{[0-9]+}} : $*Builtin.Int64
28-
// CHECK-SIL-SAME: (name "my_struct", loc "file.swift":8:9, scope {{[0-9]+}})
28+
// CHECK-SIL-SAME: (name "my_struct", loc "file.swift":8:9)
2929
// CHECK-SIL-SAME: type $MyStruct, expr op_deref:op_fragment:#MyStruct.x
3030
debug_value %3 : $*Builtin.Int64, var, (name "my_struct", loc "file.swift":8:9, scope 1), type $MyStruct, expr op_deref:op_fragment:#MyStruct.x, loc "file.swift":9:17, scope 1
3131

@@ -51,7 +51,7 @@ bb0:
5151
// CHECK: %[[MY_STRUCT:.+]] = alloca %{{.*}}MyStruct
5252
// CHECK: llvm.dbg.declare(metadata ptr %[[MY_STRUCT]], metadata ![[VAR_DECL_MD:[0-9]+]]
5353
// CHECK-SIL: alloc_stack $Int, var
54-
// CHECK-SIL-SAME: (name "my_struct", loc "file.swift":15:9, scope {{[0-9]+}})
54+
// CHECK-SIL-SAME: (name "my_struct", loc "file.swift":15:9)
5555
// CHECK-SIL-SAME: type $MyStruct, expr op_fragment:#MyStruct.x
5656
%field_x = alloc_stack $Int, var, (name "my_struct", loc "file.swift":15:9, scope 2), type $MyStruct, expr op_fragment:#MyStruct.x, loc "file.swift":16:17, scope 2
5757
// CHECK: %[[FIELD_X:.+]] = alloca %TSi

test/DebugInfo/sroa_mem2reg.sil

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -57,17 +57,17 @@ bb0(%0 : $Int64, %1 : $Int64):
5757
// CHECK-MEM2REG: %[[FIELD_Y:[0-9]+]] = struct_extract %[[STRUCT]] : $MyStruct, #MyStruct.y, loc "sroa.swift":8:21
5858
store %1 to %15 : $*Int64, loc "sroa.swift":10:17, scope 2
5959
// Make sure the struct fields' SSA values are properly connected to the source variables via op_fragment
60-
// CHECK-MEM2REG: debug_value %[[FIELD_X]] : $Int64, var, (name "my_struct", loc "sroa.swift":8:9, scope 2), type $*MyStruct, expr op_fragment:#MyStruct.x
61-
// CHECK-MEM2REG: debug_value %[[FIELD_Y]] : $Int64, var, (name "my_struct", loc "sroa.swift":8:9, scope 2), type $*MyStruct, expr op_fragment:#MyStruct.y
60+
// CHECK-MEM2REG: debug_value %[[FIELD_X]] : $Int64, var, (name "my_struct", loc "sroa.swift":8:9), type $*MyStruct, expr op_fragment:#MyStruct.x
61+
// CHECK-MEM2REG: debug_value %[[FIELD_Y]] : $Int64, var, (name "my_struct", loc "sroa.swift":8:9), type $*MyStruct, expr op_fragment:#MyStruct.y
6262
// CHECK-IR: call void @llvm.dbg.value(metadata i64 %0
6363
// CHECK-IR-SAME: metadata ![[STRUCT_MD:[0-9]+]]
6464
// CHECK-IR-SAME: !DIExpression(DW_OP_LLVM_fragment, 0, 64)
6565
// CHECK-IR: call void @llvm.dbg.value(metadata i64 %1
6666
// CHECK-IR-SAME: metadata ![[STRUCT_MD]]
6767
// CHECK-IR-SAME: !DIExpression(DW_OP_LLVM_fragment, 64, 64)
6868
// Make sure function arguments' SSA values are also properly connected to the source variables
69-
// CHECK-MEM2REG: debug_value %0 : $Int64, var, (name "my_struct", loc "sroa.swift":8:9, scope 2), type $*MyStruct, expr op_fragment:#MyStruct.x
70-
// CHECK-MEM2REG: debug_value %1 : $Int64, var, (name "my_struct", loc "sroa.swift":8:9, scope 2), type $*MyStruct, expr op_fragment:#MyStruct.y
69+
// CHECK-MEM2REG: debug_value %0 : $Int64, var, (name "my_struct", loc "sroa.swift":8:9), type $*MyStruct, expr op_fragment:#MyStruct.x
70+
// CHECK-MEM2REG: debug_value %1 : $Int64, var, (name "my_struct", loc "sroa.swift":8:9), type $*MyStruct, expr op_fragment:#MyStruct.y
7171
// CHECK-IR: call void @llvm.dbg.value(metadata i64 %0, metadata ![[ARG1_MD:[0-9]+]]
7272
// CHECK-IR: call void @llvm.dbg.value(metadata i64 %1, metadata ![[ARG2_MD:[0-9]+]]
7373
dealloc_stack %4 : $*MyStruct, loc "sroa.swift":8:9, scope 2

test/SILOptimizer/assemblyvision_remark/cast_remarks.swift

Lines changed: 6 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -35,14 +35,11 @@ public func forcedCast3<NS, T>(_ ns: NS) -> T {
3535

3636
public func forcedCast4<NS, T>(_ ns: NS, _ ns2: NS) -> T {
3737
// Make sure the colon info is right so that the arrow is under the a.
38-
//
39-
// Today, we lose that x was assigned ns2. This is flow sensitive information
40-
// that we might be able to recover. We still emit that a runtime cast
41-
// occurred here, just don't say what the underlying value was.
4238
var x = ns
4339
x = ns2
4440
return x as! T // expected-remark @:12 {{unconditional runtime cast of value with type 'NS' to 'T'}}
45-
// expected-note @-9:44 {{of 'ns2'}}
41+
// expected-note @-5:44 {{of 'ns2'}}
42+
// expected-note @-4:7 {{of 'x'}}
4643
}
4744

4845
public func condCast<NS, T>(_ ns: NS) -> T? {
@@ -73,14 +70,11 @@ public func condCast3<NS, T>(_ ns: NS) -> T? {
7370

7471
public func condCast4<NS, T>(_ ns: NS, _ ns2: NS) -> T? {
7572
// Make sure the colon info is right so that the arrow is under the a.
76-
//
77-
// Today, we lose that x was assigned ns2. This is flow sensitive information
78-
// that we might be able to recover. We still emit that a runtime cast
79-
// occurred here, just don't say what the underlying value was.
8073
var x = ns
8174
x = ns2
8275
return x as? T // expected-remark @:12 {{conditional runtime cast of value with type 'NS' to 'T'}}
83-
// expected-note @-9:42 {{of 'ns2'}}
76+
// expected-note @-5:42 {{of 'ns2'}}
77+
// expected-note @-4:7 {{of 'x'}}
8478
}
8579

8680
public func condCast5<NS, T>(_ ns: NS) -> T? {
@@ -252,6 +246,7 @@ public func forcedCast4(_ ns: Existential1, _ ns2: Existential1) -> Existential2
252246
x = ns2
253247
return x as! Existential2 // expected-remark @:12 {{unconditional runtime cast of value with type 'any Existential1' to 'any Existential2'}}
254248
// expected-note @-5:47 {{of 'ns2'}}
249+
// expected-note @-4:7 {{of 'x'}}
255250
}
256251

257252
public func condCast(_ ns: Existential1) -> Existential2? {
@@ -287,6 +282,7 @@ public func condCast4(_ ns: Existential1, _ ns2: Existential1) -> Existential2?
287282
x = ns2
288283
return x as? Existential2 // expected-remark @:12 {{conditional runtime cast of value with type 'any Existential1' to 'any Existential2'}}
289284
// expected-note @-5:45 {{of 'ns2'}}
285+
// expected-note @-4:7 {{of 'x'}}
290286
}
291287

292288
public func condCast5(_ ns: Existential1) -> Existential2? {

test/SILOptimizer/assemblyvision_remark/cast_remarks_objc.swift

Lines changed: 12 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -18,34 +18,27 @@ public func forcedCast<NS, T>(_ ns: NS) -> T {
1818

1919
public func forcedCast2<NS, T>(_ ns: NS) -> T {
2020
// Make sure the colon info is right so that the arrow is under the a.
21-
//
22-
// Today, we seem to completely eliminate 'x' here in the debug info. TODO:
23-
// Maybe we can recover this info somehow.
2421
let x = ns
2522
return x as! T // expected-remark @:12 {{unconditional runtime cast of value with type 'NS' to 'T'}}
26-
// expected-note @-7:34 {{of 'ns'}}
23+
// expected-note @-4:34 {{of 'ns'}}
24+
// expected-note @-3:7 {{of 'x'}}
2725
}
2826

2927
public func forcedCast3<NS, T>(_ ns: NS) -> T {
3028
// Make sure the colon info is right so that the arrow is under the a.
31-
//
32-
// Today, we seem to completely eliminate 'x' here in the debug info. TODO:
33-
// Maybe we can recover this info somehow.
3429
var x = ns // expected-warning {{variable 'x' was never mutated}}
3530
return x as! T // expected-remark @:12 {{unconditional runtime cast of value with type 'NS' to 'T'}}
36-
// expected-note @-7:34 {{of 'ns'}}
31+
// expected-note @-4:34 {{of 'ns'}}
32+
// expected-note @-3:7 {{of 'x'}}
3733
}
3834

3935
public func forcedCast4<NS, T>(_ ns: NS, _ ns2: NS) -> T {
4036
// Make sure the colon info is right so that the arrow is under the a.
41-
//
42-
// Today, we lose that x was assigned ns2. This is flow sensitive information
43-
// that we might be able to recover. We still emit that a runtime cast
44-
// occurred here, just don't say what the underlying value was.
4537
var x = ns
4638
x = ns2
4739
return x as! T // expected-remark @:12 {{unconditional runtime cast of value with type 'NS' to 'T'}}
48-
// expected-note @-9:44 {{of 'ns2'}}
40+
// expected-note @-5:44 {{of 'ns2'}}
41+
// expected-note @-4:7 {{of 'x'}}
4942
}
5043

5144
public func condCast<NS, T>(_ ns: NS) -> T? {
@@ -56,34 +49,27 @@ public func condCast<NS, T>(_ ns: NS) -> T? {
5649

5750
public func condCast2<NS, T>(_ ns: NS) -> T? {
5851
// Make sure the colon info is right so that the arrow is under the a.
59-
//
60-
// Today, we seem to completely eliminate 'x' here in the debug info. TODO:
61-
// Maybe we can recover this info somehow.
6252
let x = ns
6353
return x as? T // expected-remark @:12 {{conditional runtime cast of value with type 'NS' to 'T'}}
64-
// expected-note @-7:32 {{of 'ns'}}
54+
// expected-note @-4:32 {{of 'ns'}}
55+
// expected-note @-3:7 {{of 'x'}}
6556
}
6657

6758
public func condCast3<NS, T>(_ ns: NS) -> T? {
6859
// Make sure the colon info is right so that the arrow is under the a.
69-
//
70-
// Today, we seem to completely eliminate 'x' here in the debug info. TODO:
71-
// Maybe we can recover this info somehow.
7260
var x = ns // expected-warning {{variable 'x' was never mutated}}
7361
return x as? T // expected-remark @:12 {{conditional runtime cast of value with type 'NS' to 'T'}}
74-
// expected-note @-7:32 {{of 'ns'}}
62+
// expected-note @-4:32 {{of 'ns'}}
63+
// expected-note @-3:7 {{of 'x'}}
7564
}
7665

7766
public func condCast4<NS, T>(_ ns: NS, _ ns2: NS) -> T? {
7867
// Make sure the colon info is right so that the arrow is under the a.
79-
//
80-
// Today, we lose that x was assigned ns2. This is flow sensitive information
81-
// that we might be able to recover. We still emit that a runtime cast
82-
// occurred here, just don't say what the underlying value was.
8368
var x = ns
8469
x = ns2
8570
return x as? T // expected-remark @:12 {{conditional runtime cast of value with type 'NS' to 'T'}}
86-
// expected-note @-9:42 {{of 'ns2'}}
71+
// expected-note @-5:42 {{of 'ns2'}}
72+
// expected-note @-4:7 {{of 'x'}}
8773
}
8874

8975
public func condCast5<NS, T>(_ ns: NS) -> T? {

test/SILOptimizer/assemblyvision_remark/chacha.swift

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -43,9 +43,10 @@ public func run_ChaCha(_ N: Int) {
4343
// expected-remark @-1:27 {{release of type '}}
4444
}
4545
} // expected-remark {{release of type '}}
46-
46+
// expected-note @-7 {{of 'plaintext}}
4747
// expected-remark @-2 {{release of type '}}
4848
// expected-note @-16 {{of 'nonce}}
4949
// expected-remark @-4 {{release of type '}}
5050
// expected-note @-19 {{of 'key}}
5151
// expected-remark @-6 {{release of type '}}
52+
// expected-note @-18 {{of 'checkedtext}}

0 commit comments

Comments
 (0)