Skip to content

Store adjoint decls in m_Variables and rebuild references on read. NFC - #1896

Merged
vgvassilev merged 1 commit into
masterfrom
mvariables-fixme
Jul 17, 2026
Merged

Store adjoint decls in m_Variables and rebuild references on read. NFC#1896
vgvassilev merged 1 commit into
masterfrom
mvariables-fixme

Conversation

@vgvassilev

Copy link
Copy Markdown
Owner

m_Variables cached one adjoint-reference Expr per variable, and every read cloned it so the shared node was never parented twice. The cached node itself was never parented either -- a dead node per entry -- and the cross-context DeclRef rebuild was duplicated in the forward and reverse readers.

Store instead the adjoint's declaration and how the reference wraps it (AdjointInfo: a decl plus plain / *deref / (*deref)) and rebuild a fresh reference on each read through a single buildAdjoint accessor. No node is cached, so none can be shared or left dead, and the two readers share one rebuild path. StmtDiff gains a deferred build for the adjoint slot so a reverse-mode terminal leaf, which never reads the adjoint, allocates nothing. Deletes the standing m_Variables FIXME.

@codecov

codecov Bot commented Jul 16, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.

📢 Thoughts on this report? Let us know!

@github-actions github-actions Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

clang-tidy made some suggestions

/// caching one node that consumers must clone.
struct AdjointInfo {
clang::VarDecl* Decl = nullptr;
enum WrapKind { Plain, Deref, ParenDeref } Wrap = Plain;

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

warning: enum 'WrapKind' uses a larger base type ('unsigned int', size: 4 bytes) than necessary for its value set, consider using 'std::uint8_t' (1 byte) as the base type to reduce its size [performance-enum-size]

      enum WrapKind { Plain, Deref, ParenDeref } Wrap = Plain;
           ^

/// Map used to keep track of variable declarations and match them
/// with their derivatives.
std::unordered_map<const clang::ValueDecl*, clang::Expr*> m_Variables;
std::unordered_map<const clang::ValueDecl*, AdjointInfo> m_Variables;

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

warning: member variable 'm_Variables' has protected visibility [cppcoreguidelines-non-private-member-variables-in-classes]

    std::unordered_map<const clang::ValueDecl*, AdjointInfo> m_Variables;
                                                             ^

auto derivedPVDName = "_d_vector_" + std::string(PVDII->getName());
IdentifierInfo* derivedPVDII = CreateUniqueIdentifier(derivedPVDName);
Expr* derivedExpr = nullptr;
VarDecl* adjointDecl = nullptr;

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

warning: no header providing "clang::VarDecl" is directly included [misc-include-cleaner]

    VarDecl* adjointDecl = nullptr;
    ^

// carries for element access elsewhere.
Expr* paramAssignment =
BuildOp(BO_Assign, Clone(paramDiff), dVectorParam);
BuildOp(BO_Assign, buildAdjoint(m_Variables[param])->IgnoreParens(),

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

warning: no header providing "clang::BO_Assign" is directly included [misc-include-cleaner]

          BuildOp(BO_Assign, buildAdjoint(m_Variables[param])->IgnoreParens(),
                  ^

return E;
}

VisitorBase::AdjointInfo VisitorBase::adjointInfoFrom(Expr* E) {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

warning: method 'adjointInfoFrom' can be made static [readability-convert-member-functions-to-static]

  VisitorBase::AdjointInfo VisitorBase::adjointInfoFrom(Expr* E) {
                                        ^

Comment thread lib/Differentiator/VisitorBase.cpp Outdated
}
auto* VD = cast<VarDecl>(cast<DeclRefExpr>(Inner)->getDecl());
AdjointInfo::WrapKind W =
Deref ? (Paren ? AdjointInfo::ParenDeref : AdjointInfo::Deref)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

warning: conditional operator is used as sub-expression of parent conditional operator, refrain from using nested conditional operators [readability-avoid-nested-conditional-operator]

        Deref ? (Paren ? AdjointInfo::ParenDeref : AdjointInfo::Deref)
                 ^
Additional context

lib/Differentiator/VisitorBase.cpp:370: parent conditional operator here

        Deref ? (Paren ? AdjointInfo::ParenDeref : AdjointInfo::Deref)
        ^

m_Variables cached one adjoint-reference Expr per variable, and every read
cloned it so the shared node was never parented twice. The cached node itself
was never parented either -- a dead node per entry -- and the cross-context
DeclRef rebuild was duplicated in the forward and reverse readers.

Store instead the adjoint's declaration and how the reference wraps it
(AdjointInfo: a decl plus plain / *deref / (*deref)) and rebuild a fresh
reference on each read through a single buildAdjoint accessor. No node is
cached, so none can be shared or left dead, and the two readers share one
rebuild path. StmtDiff gains a deferred build for the adjoint slot so a
reverse-mode terminal leaf, which never reads the adjoint, allocates nothing.
Deletes the standing m_Variables FIXME.
@vgvassilev
vgvassilev merged commit 861aac5 into master Jul 17, 2026
40 checks passed
@vgvassilev
vgvassilev deleted the mvariables-fixme branch July 17, 2026 10:06
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant