Skip to content

Commit 6d657c9

Browse files
authored
[AutoDiff] Refine debug info emitted for adjoint buffers (#62779)
Single input variable might yield multiple adjoint buffers if control flow is involved. Therefore we cannot simply transfer debug info from the input variable: it will be invalid as we will end with multiple locations for a single "source" variable, and, even worse, might end with conflicting debug info as different buffers might be optimized differently. We do: - Drop input argument number. This must be unique and we're not - Correct variable name
1 parent 5d0a354 commit 6d657c9

File tree

3 files changed

+98
-3
lines changed

3 files changed

+98
-3
lines changed

lib/SILOptimizer/Differentiation/PullbackCloner.cpp

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -559,9 +559,23 @@ class PullbackCloner::Implementation final
559559
auto debugInfo = findDebugLocationAndVariable(originalValue);
560560
SILLocation loc = debugInfo ? debugInfo->first.getLocation()
561561
: RegularLocation::getAutoGeneratedLocation();
562+
llvm::SmallString<32> adjName;
562563
auto *newBuf = createFunctionLocalAllocation(
563564
bufType, loc, /*zeroInitialize*/ true,
564-
debugInfo.transform([](AdjointValue::DebugInfo di) { return di.second; }));
565+
debugInfo.transform(
566+
[&](AdjointValue::DebugInfo di) {
567+
llvm::raw_svector_ostream adjNameStream(adjName);
568+
SILDebugVariable &dv = di.second;
569+
dv.ArgNo = 0;
570+
adjNameStream << "derivative of '" << dv.Name << "'";
571+
if (SILDebugLocation origBBLoc = origBB->front().getDebugLocation()) {
572+
adjNameStream << " in scope at ";
573+
origBBLoc.getLocation().print(adjNameStream, getASTContext().SourceMgr);
574+
}
575+
adjNameStream << " (scope #" << origBB->getDebugID() << ")";
576+
dv.Name = adjName;
577+
return dv;
578+
}));
565579
return (insertion.first->getSecond() = newBuf);
566580
}
567581

test/AutoDiff/compiler_crashers_fixed/58660-conflicting-debug-info-inlining.swift

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
// RUN: %target-build-swift %s
22
// RUN: %target-swift-frontend -emit-sil -O -g %s | %FileCheck %s
33

4+
// REQUIRES: swift_in_compiler
5+
46
// Issue #58660: Specifically-shaped differentiable functions yield "conflicting debug info for argument" assertion failure
57
// Ensure that proper location is preserved after sil-mem2reg location-less stores (created during inlining)
68

@@ -42,9 +44,9 @@ struct MyModel: Differentiable {
4244
@differentiable(reverse)
4345
mutating func member4() {
4446
// CHECK-LABEL: // pullback of MyModel.member4()
45-
// CHECK-NOT: debug_value %{{.*}} : $MyModel.TangentVector, var, name "self", argno 1, implicit, scope
47+
// CHECK-NOT: debug_value %{{.*}} : $MyModel.TangentVector, var, name %{{.*}}, argno 1, implicit, scope
4648
// CHECK: bb1(%{{.*}} : $_AD__$s4main7MyModelV7member4yyF_bb1__PB__src_0_wrt_0):
47-
// CHECK: debug_value %{{.*}} : $MyModel.TangentVector, var, name "self", argno 1, implicit, loc
49+
// CHECK: debug_value %{{.*}} : $MyModel.TangentVector, var, name "derivative of 'self' in scope at {{.*}} (scope #1)", implicit, scope
4850
// Must be a differentiable type.
4951
var localVar: Float = 0
5052

Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,79 @@
1+
// RUN: %target-swift-frontend -emit-sil -O -g %s | %FileCheck %s
2+
3+
// REQUIRES: swift_in_compiler
4+
5+
// Fix for https://github.com/apple/swift/issues/62608
6+
// We need to emit separate debug info location for different adjoint buffers
7+
// created for the single input variable
8+
9+
import _Differentiation
10+
11+
public extension Array {
12+
@inlinable
13+
@differentiable(reverse)
14+
mutating func update(at index: Int, byCalling closure: @differentiable(reverse) (inout Element) -> Void) where Element: Differentiable {
15+
closure(&self[index])
16+
}
17+
}
18+
19+
public func valueWithPullback<T>(
20+
at x: T, of f: @differentiable(reverse) (inout T) -> Void
21+
) -> (value: Void, pullback: (inout T.TangentVector) -> Void) {
22+
@differentiable(reverse)
23+
func nonInoutWrappingFunction(_ t: T) -> T {
24+
var t = t
25+
f(&t)
26+
return t
27+
}
28+
let nonInoutPullback = pullback(at: x, of: nonInoutWrappingFunction)
29+
return ((), { $0 = nonInoutPullback($0) })
30+
}
31+
32+
@inlinable
33+
public func pullback<T>(
34+
at x: T, of f: @differentiable(reverse) (inout T) -> Void
35+
) -> (inout T.TangentVector) -> Void {
36+
return valueWithPullback(at: x, of: f).pullback
37+
}
38+
39+
// CHECK-LABEL: sil private @$s4main19testUpdateByCallingyyKF8fOfArrayL_5arraySdSaySdG_tFySdzcfU_TJpSUpSr :
40+
// CHECK: alloc_stack $Double, var, name "derivative of 'element' in scope at {{.*}} (scope #3)"
41+
// CHECK: debug_value %{{.*}} : $Builtin.FPIEEE64, var, (name "derivative of 'element' in scope at {{.*}} (scope #1)"
42+
43+
public extension Array where Element: Differentiable {
44+
@inlinable
45+
@derivative(of: update(at:byCalling:))
46+
mutating func vjpUpdate(
47+
at index: Int,
48+
byCalling closure: @differentiable(reverse) (inout Element) -> Void
49+
)
50+
->
51+
(value: Void, pullback: (inout Self.TangentVector) -> Void)
52+
{
53+
let closurePullback = pullback(at: self[index], of: closure)
54+
return (value: (), pullback: { closurePullback(&$0.base[index]) })
55+
}
56+
}
57+
58+
func testUpdateByCalling() throws {
59+
@differentiable(reverse)
60+
func fOfArray(array: [Double]) -> Double {
61+
var array = array
62+
var result = 0.0
63+
for i in withoutDerivative(at: 0 ..< array.count) {
64+
array.update(at: i, byCalling: { (element: inout Double) in
65+
let initialElement = element
66+
for _ in withoutDerivative(at: 0 ..< i) {
67+
element *= initialElement
68+
}
69+
})
70+
result += array[i]
71+
}
72+
return result
73+
}
74+
75+
let array = [Double](repeating: 1.0, count: 3)
76+
let expectedGradientOfFOfArray = [1.0, 2.0, 3.0]
77+
let obtainedGradientOfFOfArray = gradient(at: array, of: fOfArray).base
78+
}
79+

0 commit comments

Comments
 (0)