Skip to content

Commit 144950d

Browse files
committed
Refine debug info emitted for adjoint buffers.
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 60952b8 commit 144950d

File tree

3 files changed

+89
-3
lines changed

3 files changed

+89
-3
lines changed

lib/SILOptimizer/Differentiation/PullbackCloner.cpp

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -559,9 +559,18 @@ 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+
SILDebugVariable &dv = di.second;
568+
dv.ArgNo = 0;
569+
llvm::raw_svector_ostream(adjName) << "adjoint of '" << dv.Name
570+
<< "' in bb" << origBB->getDebugID();
571+
dv.Name = adjName;
572+
return dv;
573+
}));
565574
return (insertion.first->getSecond() = newBuf);
566575
}
567576

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

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -42,9 +42,9 @@ struct MyModel: Differentiable {
4242
@differentiable(reverse)
4343
mutating func member4() {
4444
// CHECK-LABEL: // pullback of MyModel.member4()
45-
// CHECK-NOT: debug_value %{{.*}} : $MyModel.TangentVector, var, name "self", argno 1, implicit, scope
45+
// CHECK-NOT: debug_value %{{.*}} : $MyModel.TangentVector, var, name %{{.*}}, argno 1, implicit, scope
4646
// CHECK: bb1(%{{.*}} : $_AD__$s4main7MyModelV7member4yyF_bb1__PB__src_0_wrt_0):
47-
// CHECK: debug_value %{{.*}} : $MyModel.TangentVector, var, name "self", argno 1, implicit, loc
47+
// CHECK: debug_value %{{.*}} : $MyModel.TangentVector, var, name "adjoint of 'self' in bb1", implicit, scope
4848
// Must be a differentiable type.
4949
var localVar: Float = 0
5050

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

0 commit comments

Comments
 (0)