Skip to content

Commit 96dca43

Browse files
authored
Merge pull request #85244 from aidan-hall/fixing-debug-info-rebase
Retain more debug info in optimized builds
2 parents 6cf36b1 + a95d297 commit 96dca43

File tree

13 files changed

+170
-8
lines changed

13 files changed

+170
-8
lines changed

SwiftCompilerSources/Sources/Optimizer/FunctionPasses/TempLValueElimination.swift

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -180,6 +180,12 @@ private func tryEliminate(copy: CopyLikeInstruction, _ context: FunctionPassCont
180180
use.set(to: copy.destinationAddress, context)
181181
}
182182
}
183+
184+
// Salvage the debug variable attribute, if present.
185+
if let debugVariable = allocStack.debugVariable {
186+
let builder = Builder(before: firstUseOfAllocStack, location: allocStack.location, context)
187+
builder.createDebugValue(value: copy.destinationAddress, debugVariable: debugVariable)
188+
}
183189
context.erase(instruction: allocStack)
184190
context.erase(instructionIncludingAllUsers: copy.loadingInstruction)
185191
}

SwiftCompilerSources/Sources/Optimizer/Utilities/OptUtils.swift

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -883,6 +883,11 @@ extension SimplifyContext {
883883
second.replace(with: replacement, self)
884884

885885
if canEraseFirst {
886+
// We only need to salvage first's debug info when !preserveDebugInfo and
887+
// it has no non-debug uses.
888+
if !preserveDebugInfo {
889+
first.salvageDebugInfo(self)
890+
}
886891
erase(instructionIncludingDebugUses: first)
887892
}
888893
}

SwiftCompilerSources/Sources/SIL/Instruction.swift

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -102,6 +102,13 @@ public class Instruction : CustomStringConvertible, Hashable {
102102
context.notifyInstructionsChanged()
103103
}
104104

105+
/// Transfer debug info associated with (the result of) this instruction to a
106+
/// new `debug_value` instruction before this instruction is deleted.
107+
public final func salvageDebugInfo(_ context: some MutatingContext) {
108+
BridgedContext.salvageDebugInfo(self.bridged)
109+
context.notifyInstructionsChanged()
110+
}
111+
105112
public var mayTrap: Bool { false }
106113

107114
final public var mayHaveSideEffects: Bool {

include/swift/SIL/SILBridging.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1554,6 +1554,7 @@ struct BridgedContext {
15541554
BRIDGED_INLINE void eraseBlock(BridgedBasicBlock block) const;
15551555
static BRIDGED_INLINE void moveInstructionBefore(BridgedInstruction inst, BridgedInstruction beforeInst);
15561556
static BRIDGED_INLINE void copyInstructionBefore(BridgedInstruction inst, BridgedInstruction beforeInst);
1557+
static BRIDGED_INLINE void salvageDebugInfo(BridgedInstruction inst);
15571558

15581559
// SSAUpdater
15591560

include/swift/SIL/SILBridgingImpl.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@
4141
#include "swift/SIL/SILVTable.h"
4242
#include "swift/SIL/SILWitnessTable.h"
4343
#include "swift/SILOptimizer/Utils/ConstExpr.h"
44+
#include "swift/SILOptimizer/Utils/DebugOptUtils.h"
4445
#include "swift/SIL/SILConstants.h"
4546
#include <stdbool.h>
4647
#include <stddef.h>
@@ -3212,6 +3213,10 @@ void BridgedContext::copyInstructionBefore(BridgedInstruction inst, BridgedInstr
32123213
inst.unbridged()->clone(beforeInst.unbridged());
32133214
}
32143215

3216+
void BridgedContext::salvageDebugInfo(BridgedInstruction inst) {
3217+
swift::salvageDebugInfo(inst.unbridged());
3218+
}
3219+
32153220
OptionalBridgedFunction BridgedContext::lookupStdlibFunction(BridgedStringRef name) const {
32163221
return {context->lookupStdlibFunction(name.unbridged())};
32173222
}

lib/SILOptimizer/Transforms/SILMem2Reg.cpp

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1968,11 +1968,16 @@ void MemoryToRegisters::removeSingleBlockAllocation(AllocStackInst *asi) {
19681968
if (!runningVals) {
19691969
// Loading from uninitialized memory is only acceptable if the type is
19701970
// empty--an aggregate of types without storage.
1971+
const auto initialValue =
1972+
createEmptyAndUndefValue(asi->getElementType(), inst, ctx);
19711973
runningVals = {
19721974
LiveValues::toReplace(asi,
1973-
/*replacement=*/createEmptyAndUndefValue(
1974-
asi->getElementType(), inst, ctx)),
1975+
/*replacement=*/initialValue),
19751976
/*isStorageValid=*/!doesLoadInvalidateStorage(inst)};
1977+
if (auto varInfo = asi->getVarInfo()) {
1978+
SILBuilderWithScope(inst, ctx).createDebugValue(
1979+
inst->getLoc(), initialValue, *varInfo);
1980+
}
19761981
}
19771982
auto *loadInst = dyn_cast<LoadInst>(inst);
19781983
if (loadInst &&

lib/SILOptimizer/Utils/CanonicalizeInstruction.cpp

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -321,9 +321,8 @@ splitAggregateLoad(LoadOperation loadInst, CanonicalizeInstruction &pass) {
321321
}
322322

323323
// Preserve the original load's debug information.
324-
if (pass.preserveDebugInfo) {
325-
swift::salvageLoadDebugInfo(loadInst);
326-
}
324+
swift::salvageLoadDebugInfo(loadInst);
325+
327326
// Remove the now unused borrows.
328327
for (auto *borrow : borrows)
329328
nextII = killInstAndIncidentalUses(borrow, nextII, pass);

lib/SILOptimizer/Utils/ConstantFolding.cpp

Lines changed: 17 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
#include "swift/SIL/PatternMatch.h"
2121
#include "swift/SIL/SILBuilder.h"
2222
#include "swift/SILOptimizer/Utils/CastOptimizer.h"
23+
#include "swift/SILOptimizer/Utils/DebugOptUtils.h"
2324
#include "swift/SILOptimizer/Utils/InstOptUtils.h"
2425
#include "swift/SILOptimizer/Utils/InstructionDeleter.h"
2526
#include "llvm/ADT/APFloat.h"
@@ -1232,8 +1233,8 @@ static SILValue constantFoldIsConcrete(BuiltinInst *BI) {
12321233
return inst;
12331234
}
12341235

1235-
SILValue swift::constantFoldBuiltin(BuiltinInst *BI,
1236-
std::optional<bool> &ResultsInError) {
1236+
static SILValue constantFoldBuiltinWithoutSalvagingDebugInfo(BuiltinInst *BI,
1237+
std::optional<bool> &ResultsInError) {
12371238
const IntrinsicInfo &Intrinsic = BI->getIntrinsicInfo();
12381239
SILModule &M = BI->getModule();
12391240

@@ -1444,6 +1445,20 @@ case BuiltinValueKind::id:
14441445
return nullptr;
14451446
}
14461447

1448+
SILValue swift::constantFoldBuiltin(BuiltinInst *BI,
1449+
std::optional<bool> &ResultsInError) {
1450+
const auto value =
1451+
constantFoldBuiltinWithoutSalvagingDebugInfo(BI, ResultsInError);
1452+
// Salvage debug info of BI arguments if it was successfully folded.
1453+
if (value) {
1454+
for (auto arg : BI->getArguments()) {
1455+
if (auto *argInst = arg.getDefiningInstruction())
1456+
swift::salvageDebugInfo(argInst);
1457+
}
1458+
}
1459+
return value;
1460+
}
1461+
14471462
/// On success this places a new value for each result of Op->getUser() into
14481463
/// Results. Results is guaranteed on success to have the same number of entries
14491464
/// as results of User. If we could only simplify /some/ of an instruction's

test/DebugInfo/self-nostorage.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
// RUN: %target-swift-frontend -primary-file %s -emit-ir -g -o - | %FileCheck %s
1+
// RUN: %target-swift-frontend -primary-file %s -emit-ir -g -O -o - | %FileCheck %s
22

33
public struct S {
44
func f() {

test/DebugInfo/sil_combine.sil

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -71,3 +71,26 @@ bb3:
7171

7272

7373
// CHECK-IR: ![[DBG_VAR]] = !DILocalVariable(name: "hello"
74+
75+
struct T {
76+
@_hasStorage let x: Builtin.Int32 { get }
77+
init(x: Builtin.Int32)
78+
}
79+
80+
// This test verifies that splitAggregateLoad in CanonicalizeInstruction.cpp
81+
// salvages debug info attached to the loaded aggregate in optimized builds.
82+
//
83+
// CHECK-LABEL: sil @split_aggregate_load : $@convention(thin) (@in T) -> Builtin.Int32 {
84+
// CHECK: bb0([[ARG:%[0-9]+]] : $*T):
85+
// CHECK-NEXT: [[ELEM_ADDR:%[0-9]+]] = struct_element_addr [[ARG]] : $*T, #T.x
86+
// CHECK-NEXT: [[ELEM:%[0-9]+]] = load [[ELEM_ADDR]]
87+
// CHECK-NEXT: debug_value [[ARG]] : $*T, let, name "var", expr op_deref
88+
// CHECK-NEXT: return [[ELEM]] : $Builtin.Int32
89+
// CHECK-LABEL: } // end sil function 'split_aggregate_load'
90+
sil @split_aggregate_load : $@convention(thin) (@in T) -> Builtin.Int32 {
91+
bb0(%0 : $*T):
92+
%1 = load %0
93+
debug_value %1, let, name "var"
94+
%2 = struct_extract %1, #T.x
95+
return %2
96+
}

0 commit comments

Comments
 (0)