Skip to content

Commit 0769766

Browse files
committed
Extract DiffScheduler to own the request graph and collector. NFC
The request graph, the analysis-context pool, the derived-function map and the collector that fills them all lived as separate CladPlugin members, threaded individually into DerivativeBuilder and reconstructed at every walk site. Group them into a DiffScheduler that CladPlugin owns and hands to DerivativeBuilder by reference. The four are one concept -- the collector needs the other three to plan a request -- so naming it leaves the plugin with its actual job of driving Sema and CodeGen. The scheduler is built on first use because it needs Sema, which is not available when the plugin is constructed. Owning RequestOptions by value rather than referencing a walk-site local is what lets the collector outlive a single walk; note in passing that it models invocation-wide defaults, not per-request state.
1 parent 6925c9f commit 0769766

9 files changed

Lines changed: 107 additions & 56 deletions

File tree

include/clad/Differentiator/DerivativeBuilder.h

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
#include "clad/Differentiator/CladUtils.h"
1313
#include "clad/Differentiator/DerivedFnCollector.h"
1414
#include "clad/Differentiator/DiffPlanner.h"
15+
#include "clad/Differentiator/DiffScheduler.h"
1516

1617
#include "clang/AST/Decl.h"
1718
#include "clang/AST/RecursiveASTVisitor.h"
@@ -111,8 +112,7 @@ struct DerivativeAndOverload {
111112
clang::Sema& m_Sema;
112113
plugin::CladPlugin& m_CladPlugin;
113114
clang::ASTContext& m_Context;
114-
DerivedFnCollector& m_DFC;
115-
clad::DynamicGraph<DiffRequest>& m_DiffRequestGraph;
115+
DiffScheduler& m_Scheduler;
116116
std::unique_ptr<utils::StmtClone> m_NodeCloner;
117117
clang::NamespaceDecl* m_BuiltinDerivativesNSD;
118118
clang::NamespaceDecl* m_NumericalDiffNSD;
@@ -177,8 +177,7 @@ struct DerivativeAndOverload {
177177

178178
public:
179179
DerivativeBuilder(clang::Sema& S, plugin::CladPlugin& P,
180-
DerivedFnCollector& DFC,
181-
clad::DynamicGraph<DiffRequest>& DRG);
180+
DiffScheduler& Scheduler);
182181
~DerivativeBuilder();
183182
/// Fuction to set the error diagnostic printing value for numerical
184183
/// differentiation.

include/clad/Differentiator/DiffPlanner.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -245,6 +245,8 @@ struct DiffRequest {
245245

246246
using DiffInterval = std::vector<clang::SourceRange>;
247247

248+
// FIXME: These are translation-unit-wide defaults taken from the compiler
249+
// invocation, not the options of a request; rename to InvocationOptions.
248250
struct RequestOptions {
249251
/// This is a flag to indicate the default behaviour to enable/disable
250252
/// TBR analysis during reverse-mode differentiation.
Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
//--------------------------------------------------------------------*- C++ -*-
2+
// clad - the C++ Clang-based Automatic Differentiator
3+
//------------------------------------------------------------------------------
4+
5+
#ifndef CLAD_DIFFERENTIATOR_DIFFSCHEDULER_H
6+
#define CLAD_DIFFERENTIATOR_DIFFSCHEDULER_H
7+
8+
#include "clad/Differentiator/DerivedFnCollector.h"
9+
#include "clad/Differentiator/DiffPlanner.h"
10+
#include "clad/Differentiator/DynamicGraph.h"
11+
12+
namespace clang {
13+
class DeclGroupRef;
14+
class Sema;
15+
} // namespace clang
16+
17+
namespace clad {
18+
19+
/// Owns the differentiation request graph and everything that builds it: the
20+
/// collector, the analysis-context pool and the derived-function map.
21+
class DiffScheduler {
22+
clang::Sema& m_Sema;
23+
RequestOptions m_Options;
24+
DiffInterval& m_Interval;
25+
DynamicGraph<DiffRequest> m_Graph;
26+
OwnedAnalysisContexts m_AllAnalysisDC;
27+
DerivedFnCollector m_DFC;
28+
DiffCollector m_Collector;
29+
30+
public:
31+
DiffScheduler(clang::Sema& S, const RequestOptions& Opts,
32+
DiffInterval& Interval)
33+
: m_Sema(S), m_Options(Opts), m_Interval(Interval),
34+
m_Collector(m_Interval, m_Graph, m_Sema, m_Options, m_AllAnalysisDC) {}
35+
36+
DynamicGraph<DiffRequest>& getGraph() { return m_Graph; }
37+
DerivedFnCollector& getDerivedFns() { return m_DFC; }
38+
39+
/// Static planning pass over a group of top-level declarations.
40+
void Plan(clang::DeclGroupRef DGR) { m_Collector.Walk(DGR); }
41+
};
42+
43+
} // namespace clad
44+
45+
#endif // CLAD_DIFFERENTIATOR_DIFFSCHEDULER_H

lib/Differentiator/BaseForwardModeVisitor.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -218,7 +218,7 @@ DerivativeAndOverload BaseForwardModeVisitor::Derive() {
218218
FunctionDecl* FoundFD =
219219
R.empty() ? nullptr : dyn_cast<FunctionDecl>(R.front());
220220
if (!RD->isLambda() && !R.empty() &&
221-
!m_Builder.m_DFC.IsCladDerivative(FoundFD)) {
221+
!m_Builder.m_Scheduler.getDerivedFns().IsCladDerivative(FoundFD)) {
222222
Sema::NestedNameSpecInfo IdInfo(RD->getIdentifier(), noLoc, noLoc,
223223
/*ObjectType=*/nullptr);
224224
// FIXME: Address nested classes where SS should be set.

lib/Differentiator/DerivativeBuilder.cpp

Lines changed: 12 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
#include "clad/Differentiator/Compatibility.h"
1515
#include "clad/Differentiator/DiffMode.h"
1616
#include "clad/Differentiator/DiffPlanner.h"
17+
#include "clad/Differentiator/DiffScheduler.h"
1718
#include "clad/Differentiator/DynamicGraph.h"
1819
#include "clad/Differentiator/ErrorEstimator.h"
1920
#include "clad/Differentiator/HessianModeVisitor.h"
@@ -58,10 +59,9 @@ using namespace clang;
5859
namespace clad {
5960

6061
DerivativeBuilder::DerivativeBuilder(clang::Sema& S, plugin::CladPlugin& P,
61-
DerivedFnCollector& DFC,
62-
clad::DynamicGraph<DiffRequest>& G)
63-
: m_Sema(S), m_CladPlugin(P), m_Context(S.getASTContext()), m_DFC(DFC),
64-
m_DiffRequestGraph(G),
62+
DiffScheduler& Scheduler)
63+
: m_Sema(S), m_CladPlugin(P), m_Context(S.getASTContext()),
64+
m_Scheduler(Scheduler),
6565
m_NodeCloner(new utils::StmtClone(m_Sema, m_Context)),
6666
m_BuiltinDerivativesNSD(nullptr), m_NumericalDiffNSD(nullptr) {}
6767

@@ -390,7 +390,7 @@ static void registerDerivative(Decl* D, Sema& S, const DiffRequest& R) {
390390
// differentiation due to unavailable definition.
391391
if (auto* CE = dyn_cast_or_null<CallExpr>(OverloadedFn))
392392
if (FunctionDecl* FD = CE->getDirectCallee())
393-
m_DFC.AddToCustomDerivativeSet(FD);
393+
m_Scheduler.getDerivedFns().AddToCustomDerivativeSet(FD);
394394
}
395395
return OverloadedFn;
396396
}
@@ -425,7 +425,8 @@ static void registerDerivative(Decl* D, Sema& S, const DiffRequest& R) {
425425
// derivative function. In that case, we should not derive the definition
426426
// again.
427427
if (derivative &&
428-
(derivative->isDefined() || m_DFC.IsCustomDerivative(derivative)))
428+
(derivative->isDefined() ||
429+
m_Scheduler.getDerivedFns().IsCustomDerivative(derivative)))
429430
alreadyDerived = true;
430431

431432
// Add the request to derive the definition of the forward mode derivative
@@ -535,7 +536,8 @@ static void registerDerivative(Decl* D, Sema& S, const DiffRequest& R) {
535536
// If only declaration is requested, allow this for clad-generated
536537
// functions or custom derivatives.
537538
if (!request.DeclarationOnly ||
538-
!(m_DFC.IsCladDerivative(FD) || m_DFC.IsCustomDerivative(FD))) {
539+
!(m_Scheduler.getDerivedFns().IsCladDerivative(FD) ||
540+
m_Scheduler.getDerivedFns().IsCustomDerivative(FD))) {
539541
const auto& name = FD->getName();
540542
// FIXME: Currently, these functions cannot be covered with custom
541543
// derivatives because templates are not well-supported in custom
@@ -647,7 +649,7 @@ static void registerDerivative(Decl* D, Sema& S, const DiffRequest& R) {
647649
// derivative is a member function it goes into an infinite loop
648650
bool isCustomDerivative = false;
649651
if (auto* FD = dyn_cast_or_null<FunctionDecl>(result.derivative))
650-
isCustomDerivative = m_DFC.IsCustomDerivative(FD);
652+
isCustomDerivative = m_Scheduler.getDerivedFns().IsCustomDerivative(FD);
651653
if (!isCustomDerivative) {
652654
if (auto* FD = result.derivative)
653655
registerDerivative(FD, m_Sema, request);
@@ -718,14 +720,14 @@ static void registerDerivative(Decl* D, Sema& S, const DiffRequest& R) {
718720

719721
FunctionDecl*
720722
DerivativeBuilder::FindDerivedFunction(const DiffRequest& request) {
721-
auto DFI = m_DFC.Find(request);
723+
auto DFI = m_Scheduler.getDerivedFns().Find(request);
722724
if (DFI.IsValid())
723725
return DFI.DerivedFn();
724726
return nullptr;
725727
}
726728

727729
void DerivativeBuilder::AddEdgeToGraph(const DiffRequest& request,
728730
bool alreadyDerived /*=false*/) {
729-
m_DiffRequestGraph.addEdgeToCurrentNode(request, alreadyDerived);
731+
m_Scheduler.getGraph().addEdgeToCurrentNode(request, alreadyDerived);
730732
}
731733
} // end namespace clad

lib/Differentiator/HessianModeVisitor.cpp

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -183,13 +183,13 @@ DerivativeAndOverload HessianModeVisitor::Derive() {
183183
utils::CreateStringLiteral(m_Context, independentArgString);
184184
FunctionDecl* DFD = nullptr;
185185
if (m_DiffReq.Mode == DiffMode::hessian_diagonal)
186-
DFD = DeriveUsingForwardModeTwice(m_Sema, m_CladPlugin, m_Builder,
187-
m_DiffReq, ForwardModeIASL,
188-
m_Builder.m_DFC);
186+
DFD = DeriveUsingForwardModeTwice(
187+
m_Sema, m_CladPlugin, m_Builder, m_DiffReq, ForwardModeIASL,
188+
m_Builder.m_Scheduler.getDerivedFns());
189189
else
190190
DFD = DeriveUsingForwardAndReverseMode(
191191
m_Sema, m_CladPlugin, m_Builder, m_DiffReq, ForwardModeIASL,
192-
m_DiffReq.Args, m_Builder.m_DFC);
192+
m_DiffReq.Args, m_Builder.m_Scheduler.getDerivedFns());
193193
secondDerivativeFuncs.push_back(DFD);
194194
}
195195
} else {
@@ -201,13 +201,13 @@ DerivativeAndOverload HessianModeVisitor::Derive() {
201201
utils::CreateStringLiteral(m_Context, PVD->getNameAsString());
202202
FunctionDecl* DFD = nullptr;
203203
if (m_DiffReq.Mode == DiffMode::hessian_diagonal)
204-
DFD = DeriveUsingForwardModeTwice(m_Sema, m_CladPlugin, m_Builder,
205-
m_DiffReq, ForwardModeIASL,
206-
m_Builder.m_DFC);
204+
DFD = DeriveUsingForwardModeTwice(
205+
m_Sema, m_CladPlugin, m_Builder, m_DiffReq, ForwardModeIASL,
206+
m_Builder.m_Scheduler.getDerivedFns());
207207
else
208208
DFD = DeriveUsingForwardAndReverseMode(
209209
m_Sema, m_CladPlugin, m_Builder, m_DiffReq, ForwardModeIASL,
210-
m_DiffReq.Args, m_Builder.m_DFC);
210+
m_DiffReq.Args, m_Builder.m_Scheduler.getDerivedFns());
211211
secondDerivativeFuncs.push_back(DFD);
212212
}
213213
}

lib/Differentiator/ReverseModeVisitor.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -378,7 +378,7 @@ Expr* ReverseModeVisitor::getStdInitListSizeExpr(const Expr* E) {
378378
FunctionDecl* FoundFD =
379379
R.empty() ? nullptr : dyn_cast<FunctionDecl>(R.front());
380380
if (!RD->isLambda() && !R.empty() &&
381-
!m_Builder.m_DFC.IsCladDerivative(FoundFD)) {
381+
!m_Builder.m_Scheduler.getDerivedFns().IsCladDerivative(FoundFD)) {
382382
Sema::NestedNameSpecInfo IdInfo(RD->getIdentifier(), noLoc, noLoc,
383383
/*ObjectType=*/nullptr);
384384
// FIXME: Address nested classes where SS should be set.

tools/ClangPlugin.cpp

Lines changed: 27 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -206,9 +206,6 @@ void InitTimers();
206206
if (!CheckBuiltins())
207207
return;
208208
#if CLANG_VERSION_MAJOR > 16
209-
Sema& S = m_CI.getSema();
210-
RequestOptions opts{};
211-
SetRequestOptions(opts);
212209
// Traverse all constexpr FunctionDecls for the static graph only once to
213210
// differentiate them immeditely.
214211
{
@@ -218,19 +215,17 @@ void InitTimers();
218215
continue;
219216
auto* FD = cast<FunctionDecl>(D);
220217
if (FD->isConstexpr() || !m_Multiplexer) {
221-
DiffCollector collector(CladEnabledRange, m_DiffRequestGraph, S,
222-
opts, m_AllAnalysisDC);
223-
collector.Walk(DGR);
218+
getScheduler().Plan(DGR);
224219
break;
225220
}
226221
}
227222
}
228223

229-
for (DiffRequest& request : m_DiffRequestGraph.getNodes()) {
224+
for (DiffRequest& request : getScheduler().getGraph().getNodes()) {
230225
if (request.ImmediateMode && request.Function->isConstexpr()) {
231-
m_DiffRequestGraph.setCurrentProcessingNode(request);
226+
getScheduler().getGraph().setCurrentProcessingNode(request);
232227
ProcessDiffRequest(request);
233-
m_DiffRequestGraph.markCurrentNodeProcessed();
228+
getScheduler().getGraph().markCurrentNodeProcessed();
234229
}
235230
}
236231
#endif
@@ -349,8 +344,8 @@ void InitTimers();
349344
FunctionDecl* CladPlugin::ProcessDiffRequest(DiffRequest& request) {
350345
Sema& S = m_CI.getSema();
351346
if (!m_DerivativeBuilder)
352-
m_DerivativeBuilder = std::make_unique<DerivativeBuilder>(
353-
S, *this, m_DFC, m_DiffRequestGraph);
347+
m_DerivativeBuilder =
348+
std::make_unique<DerivativeBuilder>(S, *this, getScheduler());
354349

355350
if (request.Global) {
356351
auto deriveResult = m_DerivativeBuilder->Derive(request);
@@ -366,7 +361,7 @@ void InitTimers();
366361
// FIXME: These requests are not fully generated in the diffplanner and we
367362
// have to update diff params on this stage.
368363
if (request.CurrentDerivativeOrder > 1 ||
369-
m_DFC.IsCladDerivative(request.Function))
364+
getScheduler().getDerivedFns().IsCladDerivative(request.Function))
370365
request.UpdateDiffParamsInfo(m_CI.getSema());
371366
const FunctionDecl* FD = request.Function;
372367
ASTContext& C = S.getASTContext();
@@ -397,7 +392,7 @@ void InitTimers();
397392
{
398393
llvm::SaveAndRestore<unsigned> Saved(request.RequestedDerivativeOrder,
399394
1);
400-
auto DFI = m_DFC.Find(request);
395+
auto DFI = getScheduler().getDerivedFns().Find(request);
401396
if (DFI.IsValid()) {
402397
DerivativeDecl = DFI.DerivedFn();
403398
OverloadedDerivativeDecl = DFI.OverloadedDerivedFn();
@@ -413,8 +408,8 @@ void InitTimers();
413408
utils::hasEmptyBody(DerivativeDecl))
414409
return nullptr;
415410
if (DerivativeDecl)
416-
m_DFC.Add(DerivedFnInfo(request, DerivativeDecl,
417-
OverloadedDerivativeDecl));
411+
getScheduler().getDerivedFns().Add(DerivedFnInfo(
412+
request, DerivativeDecl, OverloadedDerivativeDecl));
418413
}
419414
}
420415

@@ -595,6 +590,16 @@ void InitTimers();
595590
SetUsefulAnalysisOptions(m_DO, opts);
596591
}
597592

593+
DiffScheduler& CladPlugin::getScheduler() {
594+
if (!m_Scheduler) {
595+
RequestOptions Opts{};
596+
SetRequestOptions(Opts);
597+
m_Scheduler = std::make_unique<DiffScheduler>(m_CI.getSema(), Opts,
598+
CladEnabledRange);
599+
}
600+
return *m_Scheduler;
601+
}
602+
598603
void CladPlugin::FinalizeTranslationUnit() {
599604
Sema& S = m_CI.getSema();
600605
// Restore the TUScope that became a 0 in Sema::ActOnEndOfTranslationUnit.
@@ -606,16 +611,16 @@ void InitTimers();
606611
Sema::LocalEagerInstantiationScope LocalInstantiations(
607612
S CLAD_COMPAT_CLANG21_AtEndOfTUParam);
608613

609-
if (!m_DiffRequestGraph.isProcessingNode()) {
614+
if (!getScheduler().getGraph().isProcessingNode()) {
610615
// This check is to avoid recursive processing of the graph, as
611616
// HandleTopLevelDecl can be called recursively in non-standard
612617
// setup for code generation.
613-
DiffRequest request = m_DiffRequestGraph.getNextToProcessNode();
618+
DiffRequest request = getScheduler().getGraph().getNextToProcessNode();
614619
while (request.Function || request.Global) {
615-
m_DiffRequestGraph.setCurrentProcessingNode(request);
620+
getScheduler().getGraph().setCurrentProcessingNode(request);
616621
ProcessDiffRequest(request);
617-
m_DiffRequestGraph.markCurrentNodeProcessed();
618-
request = m_DiffRequestGraph.getNextToProcessNode();
622+
getScheduler().getGraph().markCurrentNodeProcessed();
623+
request = getScheduler().getGraph().getNextToProcessNode();
619624
}
620625
}
621626

@@ -631,9 +636,6 @@ void InitTimers();
631636
void CladPlugin::HandleTranslationUnit(ASTContext& C) {
632637
// In case of diagnostics, don't bother, just let the compiler finish.
633638
if (!m_CI.getDiagnostics().hasErrorOccurred()) {
634-
Sema& S = m_CI.getSema();
635-
RequestOptions opts{};
636-
SetRequestOptions(opts);
637639
// Traverse all collected DeclGroupRef only once to create the static
638640
// graph.
639641
TimedAnalysisRegion R("Rest of TU");
@@ -642,16 +644,14 @@ void InitTimers();
642644
if (const auto* FD = dyn_cast<FunctionDecl>(D))
643645
if (FD->isConstexpr())
644646
continue;
645-
DiffCollector collector(CladEnabledRange, m_DiffRequestGraph, S,
646-
opts, m_AllAnalysisDC);
647-
collector.Walk(DCI.m_DGR);
647+
getScheduler().Plan(DCI.m_DGR);
648648
break;
649649
}
650650

651651
if (m_CI.getFrontendOpts().ShowStats) {
652652
// Print the graph of the diff requests.
653653
llvm::errs() << "\n*** INFORMATION ABOUT THE DIFF REQUESTS\n";
654-
m_DiffRequestGraph.dump();
654+
getScheduler().getGraph().dump();
655655
}
656656

657657
FinalizeTranslationUnit();

tools/ClangPlugin.h

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
#include "clad/Differentiator/DerivedFnCollector.h"
1212
#include "clad/Differentiator/DiffMode.h"
1313
#include "clad/Differentiator/DiffPlanner.h"
14+
#include "clad/Differentiator/DiffScheduler.h"
1415
#include "clad/Differentiator/Version.h"
1516

1617
#include "clang/AST/Decl.h"
@@ -97,9 +98,9 @@ struct DifferentiationOptions {
9798
DifferentiationOptions m_DO;
9899
std::unique_ptr<DerivativeBuilder> m_DerivativeBuilder;
99100
bool m_HasRuntime = false;
100-
DerivedFnCollector m_DFC;
101-
DynamicGraph<DiffRequest> m_DiffRequestGraph;
102-
OwnedAnalysisContexts m_AllAnalysisDC;
101+
/// Lazily constructed because it needs Sema, which is not available
102+
/// until InitializeSema; reach it through getScheduler().
103+
std::unique_ptr<DiffScheduler> m_Scheduler;
103104
enum class CallKind {
104105
HandleCXXStaticMemberVarInstantiation,
105106
HandleTopLevelDecl,
@@ -168,8 +169,9 @@ struct DifferentiationOptions {
168169
// setup, we exit early to give control to the non-standard setup for
169170
// code generation.
170171
// FIXME: This should go away if Cling starts using the clang driver.
171-
if (!m_Multiplexer &&
172-
(m_DFC.IsCladDerivative(FD) || m_DFC.IsCustomDerivative(FD)))
172+
if (!m_Multiplexer && m_Scheduler &&
173+
(m_Scheduler->getDerivedFns().IsCladDerivative(FD) ||
174+
m_Scheduler->getDerivedFns().IsCustomDerivative(FD)))
173175
return true;
174176

175177
HandleTopLevelDeclForClad(D);
@@ -252,6 +254,7 @@ struct DifferentiationOptions {
252254
clang::FunctionDecl* ProcessDiffRequest(DiffRequest& request);
253255

254256
private:
257+
DiffScheduler& getScheduler();
255258
void AppendDelayed(DelayedCallInfo DCI) {
256259
// Incremental processing handles the translation unit in chunks and it is
257260
// expected to have multiple calls to this functionality.

0 commit comments

Comments
 (0)