Skip to content

Commit 3cbe474

Browse files
authored
Give the _d_this and independent-var-count caches leak-free references. NFC (#1895)
Two per-derivative caches were handed to several consumers as one Expr node that must not be parented twice -- m_ThisExprDerivative (the `_d_this` adjoint) and the independent-variable count. A consumer that forgot to copy reintroduced the sharing findSharedNode now asserts against. Route _d_this through a cloneThisExprDerivative() accessor that clones on read: it is a reused compound expression, so a structural copy is the right tool. For the count, cache the indepVarCount VarDecl (m_IndVarCountDecl) instead of a DeclRef to it and rebuild a fresh reference on every read -- a DeclRef is trivially rebuilt, so no node is shared and nothing is cloned, the discipline the m_Variables FIXME asks for. Its accumulator becomes a local threaded out of BuildVectorModeParams.
1 parent db3ae21 commit 3cbe474

6 files changed

Lines changed: 68 additions & 57 deletions

File tree

include/clad/Differentiator/VectorForwardModeVisitor.h

Lines changed: 9 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -17,11 +17,13 @@ class VectorForwardModeVisitor : public BaseForwardModeVisitor {
1717
/// m_Variables map because all other intermediate variables will have
1818
/// derivatives as vectors.
1919
std::unordered_map<const clang::ValueDecl*, clang::Expr*> m_ParamVariables;
20-
/// Expression for total number of independent variables. This also includes
21-
/// the size of array independent variables which will be inferred from the
22-
/// size of the corresponding clad array they provide at runtime for storing
23-
/// the derivatives.
24-
clang::Expr* m_IndVarCountExpr;
20+
/// The generated `indepVarCount` variable (total number of independent
21+
/// variables). Cached as the decl so each read rebuilds a fresh DeclRef
22+
/// instead of sharing one node.
23+
clang::VarDecl* m_IndVarCountDecl = nullptr;
24+
25+
/// Build a fresh reference to the independent-variable-count variable.
26+
clang::Expr* buildIndVarCountRef() { return BuildDeclRef(m_IndVarCountDecl); }
2527

2628
public:
2729
VectorForwardModeVisitor(DerivativeBuilder& builder,
@@ -55,7 +57,7 @@ class VectorForwardModeVisitor : public BaseForwardModeVisitor {
5557
/// function parameter types and the differentiation mode are implicitly
5658
/// taken from the data member variables.
5759
llvm::SmallVector<clang::ParmVarDecl*, 8>
58-
BuildVectorModeParams(DiffParams& diffParams);
60+
BuildVectorModeParams(DiffParams& diffParams, clang::Expr*& indVarCountExpr);
5961

6062
/// Get an expression used to initialize the one-hot vector for the
6163
/// given index and size. A one-hot vector is a vector with all elements
@@ -83,8 +85,7 @@ class VectorForwardModeVisitor : public BaseForwardModeVisitor {
8385
std::string GetPushForwardFunctionSuffix() override;
8486
DiffMode GetPushForwardMode() override;
8587

86-
// Function for setting the independent variables for vector mode.
87-
void SetIndependentVarsExpr(clang::Expr* IndVarCountExpr);
88+
void SetIndependentVarCountDecl(clang::VarDecl* VD);
8889
};
8990
} // end namespace clad
9091

include/clad/Differentiator/VisitorBase.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -795,6 +795,11 @@ namespace clad {
795795
clang::Expr* CloneNode(const clang::Expr* E);
796796
/// Statement overload of the structural copy above.
797797
clang::Stmt* CloneNode(const clang::Stmt* S);
798+
/// Return a fresh clone of the cached `_d_this` adjoint reference, so each
799+
/// consumer owns its copy and never parents the one cached node twice.
800+
clang::Expr* cloneThisExprDerivative() {
801+
return CloneNode(m_ThisExprDerivative);
802+
}
798803
/// A deferred CloneNode(\p N): the clone is produced only if the StmtDiff
799804
/// representation it is stored in is actually read, so a representation no
800805
/// consumer needs allocates no orphaned clone. Drop-in for CloneNode(N) in

lib/Differentiator/JacobianModeVisitor.cpp

Lines changed: 20 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,10 @@ DerivativeAndOverload JacobianModeVisitor::Derive() {
6666
// differentiation.
6767
size_t nonArrayIndVarCount = 0;
6868

69+
// Running sum of independent-variable counts, materialized into the
70+
// m_IndVarCountDecl variable below.
71+
Expr* indVarCountExpr = nullptr;
72+
6973
// Set the parameters for the derivative.
7074
llvm::SmallVector<ParmVarDecl*, 16> params;
7175
llvm::SmallVector<ParmVarDecl*, 16> derivedParams;
@@ -100,11 +104,11 @@ DerivativeAndOverload JacobianModeVisitor::Derive() {
100104
/*MemberFunctionName=*/"rows", {});
101105
llvm::StringRef PVDName = PVD->getName();
102106
if (!PVDName.contains("_clad_out_")) {
103-
if (!m_IndVarCountExpr)
104-
m_IndVarCountExpr = getSize;
107+
if (!indVarCountExpr)
108+
indVarCountExpr = getSize;
105109
else
106-
m_IndVarCountExpr =
107-
BuildOp(BinaryOperatorKind::BO_Add, m_IndVarCountExpr, getSize);
110+
indVarCountExpr =
111+
BuildOp(BinaryOperatorKind::BO_Add, indVarCountExpr, getSize);
108112
}
109113
} else if (PVD->getType()->isReferenceType()) {
110114
ParmVarDecl* derivedPVD =
@@ -136,11 +140,11 @@ DerivativeAndOverload JacobianModeVisitor::Derive() {
136140
// of non-array parameters.
137141
Expr* nonArrayIndVarCountExpr = ConstantFolder::synthesizeLiteral(
138142
m_Context.UnsignedLongTy, m_Context, nonArrayIndVarCount);
139-
if (!m_IndVarCountExpr) {
140-
m_IndVarCountExpr = nonArrayIndVarCountExpr;
143+
if (!indVarCountExpr) {
144+
indVarCountExpr = nonArrayIndVarCountExpr;
141145
} else if (nonArrayIndVarCount != 0) {
142-
m_IndVarCountExpr = BuildOp(BinaryOperatorKind::BO_Add, m_IndVarCountExpr,
143-
nonArrayIndVarCountExpr);
146+
indVarCountExpr = BuildOp(BinaryOperatorKind::BO_Add, indVarCountExpr,
147+
nonArrayIndVarCountExpr);
144148
}
145149

146150
vectorDiffFD->setParams(
@@ -149,11 +153,11 @@ DerivativeAndOverload JacobianModeVisitor::Derive() {
149153

150154
// Instantiate a variable indepVarCount to store the total number of
151155
// independent variables requested.
152-
// size_t indepVarCount = m_IndVarCountExpr;
153-
auto* totalIndVars = BuildVarDecl(m_Context.UnsignedLongTy, "indepVarCount",
154-
m_IndVarCountExpr);
156+
// size_t indepVarCount = indVarCountExpr;
157+
auto* totalIndVars =
158+
BuildVarDecl(m_Context.UnsignedLongTy, "indepVarCount", indVarCountExpr);
155159
addToCurrentBlock(BuildDeclStmt(totalIndVars));
156-
m_IndVarCountExpr = BuildDeclRef(totalIndVars);
160+
m_IndVarCountDecl = totalIndVars;
157161

158162
for (DeclStmt* decl : adjointDecls)
159163
addToCurrentBlock(decl);
@@ -201,8 +205,8 @@ DerivativeAndOverload JacobianModeVisitor::Derive() {
201205
// Create an identity matrix for the parameter,
202206
// with number of rows equal to the size of the array,
203207
// and number of columns equal to the number of independent variables
204-
llvm::SmallVector<Expr*, 3> args = {
205-
getSize, CloneNode(m_IndVarCountExpr), offsetExpr};
208+
llvm::SmallVector<Expr*, 3> args = {getSize, buildIndVarCountRef(),
209+
offsetExpr};
206210
dVectorParam = BuildIdentityMatrixExpr(dParamType, args, loc);
207211

208212
// Update the array independent expression. getSize is already used by
@@ -215,8 +219,7 @@ DerivativeAndOverload JacobianModeVisitor::Derive() {
215219
CloneNode(getSize));
216220
} else {
217221
// Create a one hot vector for the parameter.
218-
llvm::SmallVector<Expr*, 2> args = {CloneNode(m_IndVarCountExpr),
219-
offsetExpr};
222+
llvm::SmallVector<Expr*, 2> args = {buildIndVarCountRef(), offsetExpr};
220223
dVectorParam = BuildCallExprToCladFunction("one_hot_vector", args,
221224
{dParamType}, loc);
222225
++nonArrayIndVarCount;
@@ -229,7 +232,7 @@ DerivativeAndOverload JacobianModeVisitor::Derive() {
229232
continue;
230233
// This parameter is not an independent variable.
231234
// Initialize by all zeros.
232-
Expr* dCount = CloneNode(m_IndVarCountExpr);
235+
Expr* dCount = buildIndVarCountRef();
233236
dVectorParam = BuildCallExprToCladFunction("zero_vector", {dCount},
234237
{dParamType}, loc);
235238
}

lib/Differentiator/ReverseModeVisitor.cpp

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -580,7 +580,7 @@ Expr* ReverseModeVisitor::getStdInitListSizeExpr(const Expr* E) {
580580
// ```
581581
if (!CI->isMemberInitializer()) {
582582
beginBlock(direction::reverse);
583-
Expr* dthisObj = BuildOp(UO_Deref, CloneNode(m_ThisExprDerivative));
583+
Expr* dthisObj = BuildOp(UO_Deref, cloneThisExprDerivative());
584584
StmtDiff initDiff = Visit(CI->getInit(), dthisObj);
585585
// Build the placement new.
586586
Expr* initCall = nullptr;
@@ -618,7 +618,7 @@ Expr* ReverseModeVisitor::getStdInitListSizeExpr(const Expr* E) {
618618
}
619619
llvm::StringRef fieldName = CI->getMember()->getName();
620620
Expr* memberDiff = utils::BuildMemberExpr(
621-
m_Sema, getCurrentScope(), CloneNode(m_ThisExprDerivative), fieldName);
621+
m_Sema, getCurrentScope(), cloneThisExprDerivative(), fieldName);
622622

623623
beginBlock(direction::reverse);
624624
QualType memberTy = CI->getMember()->getType();
@@ -635,9 +635,8 @@ Expr* ReverseModeVisitor::getStdInitListSizeExpr(const Expr* E) {
635635
Expr* member = utils::BuildMemberExpr(m_Sema, getCurrentScope(), thisExpr,
636636
fieldName);
637637
init = BuildOp(BO_Assign, member, initDiff.getExpr());
638-
Expr* memberDx =
639-
utils::BuildMemberExpr(m_Sema, getCurrentScope(),
640-
CloneNode(m_ThisExprDerivative), fieldName);
638+
Expr* memberDx = utils::BuildMemberExpr(
639+
m_Sema, getCurrentScope(), cloneThisExprDerivative(), fieldName);
641640
if (!memberDx->getType()->isRealType())
642641
initDx = BuildOp(BO_Assign, memberDx, initDiff.getExpr_dx());
643642
}
@@ -4778,7 +4777,7 @@ Expr* ReverseModeVisitor::getStdInitListSizeExpr(const Expr* E) {
47784777
}
47794778
// m_ThisExprDerivative is a single cached `_d_this` ref; hand out a fresh
47804779
// clone so distinct member accesses do not share the same base node.
4781-
return {clonedCTE, CloneNode(m_ThisExprDerivative)};
4780+
return {clonedCTE, cloneThisExprDerivative()};
47824781
}
47834782

47844783
StmtDiff ReverseModeVisitor::VisitCXXTemporaryObjectExpr(

lib/Differentiator/VectorForwardModeVisitor.cpp

Lines changed: 28 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ using namespace clang;
1616
namespace clad {
1717
VectorForwardModeVisitor::VectorForwardModeVisitor(DerivativeBuilder& builder,
1818
const DiffRequest& request)
19-
: BaseForwardModeVisitor(builder, request), m_IndVarCountExpr(nullptr) {}
19+
: BaseForwardModeVisitor(builder, request) {}
2020

2121
VectorForwardModeVisitor::~VectorForwardModeVisitor() {}
2222

@@ -28,8 +28,8 @@ DiffMode VectorForwardModeVisitor::GetPushForwardMode() {
2828
return DiffMode::vector_pushforward;
2929
}
3030

31-
void VectorForwardModeVisitor::SetIndependentVarsExpr(Expr* IndVarCountExpr) {
32-
m_IndVarCountExpr = IndVarCountExpr;
31+
void VectorForwardModeVisitor::SetIndependentVarCountDecl(VarDecl* VD) {
32+
m_IndVarCountDecl = VD;
3333
}
3434

3535
DerivativeAndOverload VectorForwardModeVisitor::Derive() {
@@ -70,7 +70,10 @@ DerivativeAndOverload VectorForwardModeVisitor::Derive() {
7070
DiffParams args{};
7171
for (const auto& dParam : m_DiffReq.DVI)
7272
args.push_back(dParam.param);
73-
auto params = BuildVectorModeParams(args);
73+
// Running sum of independent-variable counts, filled in by
74+
// BuildVectorModeParams and materialized into m_IndVarCountDecl below.
75+
Expr* indVarCountExpr = nullptr;
76+
auto params = BuildVectorModeParams(args, indVarCountExpr);
7477
vectorDiffFD->setParams(
7578
clad_compat::makeArrayRef(params.data(), params.size()));
7679
vectorDiffFD->setBody(nullptr);
@@ -82,11 +85,11 @@ DerivativeAndOverload VectorForwardModeVisitor::Derive() {
8285

8386
// Instantiate a variable indepVarCount to store the total number of
8487
// independent variables requested.
85-
// size_t indepVarCount = m_IndVarCountExpr;
86-
auto* totalIndVars = BuildVarDecl(m_Context.UnsignedLongTy, "indepVarCount",
87-
m_IndVarCountExpr);
88+
// size_t indepVarCount = indVarCountExpr;
89+
auto* totalIndVars =
90+
BuildVarDecl(m_Context.UnsignedLongTy, "indepVarCount", indVarCountExpr);
8891
addToCurrentBlock(BuildDeclStmt(totalIndVars));
89-
m_IndVarCountExpr = BuildDeclRef(totalIndVars);
92+
m_IndVarCountDecl = totalIndVars;
9093

9194
// Expression for maintaining the number of independent variables processed
9295
// till now present as array elements. This will be sum of sizes of all such
@@ -128,8 +131,8 @@ DerivativeAndOverload VectorForwardModeVisitor::Derive() {
128131
// Create an identity matrix for the parameter,
129132
// with number of rows equal to the size of the array,
130133
// and number of columns equal to the number of independent variables
131-
llvm::SmallVector<Expr*, 3> args = {
132-
getSize, CloneNode(m_IndVarCountExpr), offsetExpr};
134+
llvm::SmallVector<Expr*, 3> args = {getSize, buildIndVarCountRef(),
135+
offsetExpr};
133136
dVectorParam = BuildIdentityMatrixExpr(dParamType, args, loc);
134137

135138
// Update the array independent expression. getSize is already used by
@@ -144,8 +147,7 @@ DerivativeAndOverload VectorForwardModeVisitor::Derive() {
144147
}
145148
} else {
146149
// Create a one hot vector for the parameter.
147-
llvm::SmallVector<Expr*, 2> args = {CloneNode(m_IndVarCountExpr),
148-
offsetExpr};
150+
llvm::SmallVector<Expr*, 2> args = {buildIndVarCountRef(), offsetExpr};
149151
dVectorParam = BuildCallExprToCladFunction("one_hot_vector", args,
150152
{dParamType}, loc);
151153
++nonArrayIndVarCount;
@@ -158,7 +160,7 @@ DerivativeAndOverload VectorForwardModeVisitor::Derive() {
158160
continue;
159161
// This parameter is not an independent variable.
160162
// Initialize by all zeros.
161-
Expr* dCount = CloneNode(m_IndVarCountExpr);
163+
Expr* dCount = buildIndVarCountRef();
162164
dVectorParam = BuildCallExprToCladFunction("zero_vector", {dCount},
163165
{dParamType}, loc);
164166
}
@@ -356,7 +358,8 @@ VectorForwardModeVisitor::CreateVectorModeOverload(FunctionDecl* derivative) {
356358
}
357359

358360
llvm::SmallVector<clang::ParmVarDecl*, 8>
359-
VectorForwardModeVisitor::BuildVectorModeParams(DiffParams& diffParams) {
361+
VectorForwardModeVisitor::BuildVectorModeParams(DiffParams& diffParams,
362+
Expr*& indVarCountExpr) {
360363
llvm::SmallVector<clang::ParmVarDecl*, 8> params, paramDerivatives;
361364
params.reserve(m_DiffReq->getNumParams() + diffParams.size());
362365
auto derivativeFnType = cast<FunctionProtoType>(m_Derivative->getType());
@@ -395,14 +398,14 @@ VectorForwardModeVisitor::BuildVectorModeParams(DiffParams& diffParams) {
395398
if (utils::isArrayOrPointerType(PVD->getType())) {
396399
m_ParamVariables[*it] = (Expr*)BuildDeclRef(dPVD);
397400
// dPVD will be a clad::array or clad::array_ref, both have size() method.
398-
// If m_IndVarCountExpr is null, initialize it with dPVD.size().
401+
// If indVarCountExpr is null, initialize it with dPVD.size().
399402
// Otherwise, increment it by dPVD.size().
400403
Expr* getSize = BuildArrayRefSizeExpr(m_ParamVariables[*it]);
401-
if (!m_IndVarCountExpr) {
402-
m_IndVarCountExpr = getSize;
404+
if (!indVarCountExpr) {
405+
indVarCountExpr = getSize;
403406
} else {
404-
m_IndVarCountExpr =
405-
BuildOp(BinaryOperatorKind::BO_Add, m_IndVarCountExpr, getSize);
407+
indVarCountExpr =
408+
BuildOp(BinaryOperatorKind::BO_Add, indVarCountExpr, getSize);
406409
}
407410
} else {
408411
m_ParamVariables[*it] = BuildOp(UO_Deref, BuildDeclRef(dPVD), noLoc);
@@ -415,11 +418,11 @@ VectorForwardModeVisitor::BuildVectorModeParams(DiffParams& diffParams) {
415418
// of non-array parameters.
416419
Expr* nonArrayIndVarCountExpr = ConstantFolder::synthesizeLiteral(
417420
m_Context.UnsignedLongTy, m_Context, nonArrayIndVarCount);
418-
if (!m_IndVarCountExpr) {
419-
m_IndVarCountExpr = nonArrayIndVarCountExpr;
421+
if (!indVarCountExpr) {
422+
indVarCountExpr = nonArrayIndVarCountExpr;
420423
} else if (nonArrayIndVarCount != 0) {
421-
m_IndVarCountExpr = BuildOp(BinaryOperatorKind::BO_Add, m_IndVarCountExpr,
422-
nonArrayIndVarCountExpr);
424+
indVarCountExpr = BuildOp(BinaryOperatorKind::BO_Add, indVarCountExpr,
425+
nonArrayIndVarCountExpr);
423426
}
424427

425428
// insert the derivative parameters at the end of the parameter list.
@@ -564,7 +567,7 @@ VectorForwardModeVisitor::DifferentiateVarDecl(const VarDecl* VD) {
564567
StmtDiff VectorForwardModeVisitor::VisitFloatingLiteral(
565568
const clang::FloatingLiteral* FL) {
566569
SourceLocation fakeLoc = utils::GetValidSLoc(m_Sema);
567-
Expr* dCount = CloneNode(m_IndVarCountExpr);
570+
Expr* dCount = buildIndVarCountRef();
568571
auto* zero_vec = BuildCallExprToCladFunction("zero_vector", {dCount},
569572
{FL->getType()}, fakeLoc);
570573
return StmtDiff(Clone(FL), zero_vec);
@@ -573,7 +576,7 @@ StmtDiff VectorForwardModeVisitor::VisitFloatingLiteral(
573576
StmtDiff
574577
VectorForwardModeVisitor::VisitIntegerLiteral(const clang::IntegerLiteral* IL) {
575578
SourceLocation fakeLoc = utils::GetValidSLoc(m_Sema);
576-
Expr* dCount = CloneNode(m_IndVarCountExpr);
579+
Expr* dCount = buildIndVarCountRef();
577580
auto* zero_vec = BuildCallExprToCladFunction("zero_vector", {dCount},
578581
{IL->getType()}, fakeLoc);
579582
return StmtDiff(Clone(IL), zero_vec);

lib/Differentiator/VectorPushForwardModeVisitor.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,7 @@ void VectorPushForwardModeVisitor::ExecuteInsidePushforwardFunctionBlock() {
4343
auto* totalIndVars =
4444
BuildVarDecl(m_Context.UnsignedLongTy, "indepVarCount", indVarCountExpr);
4545
addToCurrentBlock(BuildDeclStmt(totalIndVars));
46-
SetIndependentVarsExpr(BuildDeclRef(totalIndVars));
46+
SetIndependentVarCountDecl(totalIndVars);
4747

4848
BaseForwardModeVisitor::ExecuteInsidePushforwardFunctionBlock();
4949
}

0 commit comments

Comments
 (0)