Skip to content

Route memory-builtin recognition through AllocCallInfo. NFC - #1935

Merged
vgvassilev merged 1 commit into
masterfrom
refactor-allocs
Jul 31, 2026
Merged

Route memory-builtin recognition through AllocCallInfo. NFC#1935
vgvassilev merged 1 commit into
masterfrom
refactor-allocs

Conversation

@vgvassilev

Copy link
Copy Markdown
Owner

Reverse mode recognised malloc/calloc/realloc by ad-hoc name-string checks in two places: CheckAndBuildCallToMemset re-parsed the RHS for the memset size, and the in-place-realloc test re-parsed it again for the store/restore skip. The two walked the same call independently and are easy to drift apart.

Introduce a small AllocCallInfo recognizer that classifies a heap-memory builtin once and owns the per-op invariants -- the memset byte-size operand (malloc arg0 / realloc arg1; calloc self-zeroes) and the in-place realloc check (LHS is realloc's own pointer argument). Both sites now go through it. No functional change: the growing realloc stays valgrind clean and the shrinking case is unchanged.

@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

// one place instead of ad-hoc name checks scattered across the visitor.
class AllocCallInfo {
public:
enum class Kind { None, Malloc, Calloc, Realloc, Free };

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 'Kind' uses a larger base type ('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 class Kind { None, Malloc, Calloc, Realloc, Free };
               ^

const clang::FunctionDecl* FD = CE->getDirectCallee();
if (!FD)
return {};
Kind k = llvm::StringSwitch<Kind>(FD->getName())

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 "llvm::StringSwitch" is directly included [misc-include-cleaner]

lib/Differentiator/ReverseModeVisitor.cpp:68:

- #include <memory>
+ #include <llvm/ADT/StringSwitch.h>
+ #include <memory>

return AllocCallInfo(k, CE);
}

Kind kind() const { return Kind_; }

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: function 'kind' should be marked [[nodiscard]] [modernize-use-nodiscard]

Suggested change
Kind kind() const { return Kind_; }
[[nodiscard]] Kind kind() const { return Kind_; }

}

Kind kind() const { return Kind_; }
clang::CallExpr* call() const { return Call_; }

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: function 'call' should be marked [[nodiscard]] [modernize-use-nodiscard]

Suggested change
clang::CallExpr* call() const { return Call_; }
[[nodiscard]] clang::CallExpr* call() const { return Call_; }

// The number-of-bytes operand that a following memset must zero:
// malloc(n) -> n, realloc(p, n) -> n. calloc self-zeroes and needs no
// memset, so it (and free/none) report null here.
clang::Expr* memsetByteSize() const {

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: function 'memsetByteSize' should be marked [[nodiscard]] [modernize-use-nodiscard]

Suggested change
clang::Expr* memsetByteSize() const {
[[nodiscard]] clang::Expr* memsetByteSize() const {


private:
AllocCallInfo(Kind k, clang::CallExpr* c) : Kind_(k), Call_(c) {}
Kind Kind_ = Kind::None;

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: invalid case style for private member 'Kind_' [readability-identifier-naming]

lib/Differentiator/ReverseModeVisitor.cpp:269:

-     Kind kind() const { return Kind_; }
+     Kind kind() const { return m_Kind; }

lib/Differentiator/ReverseModeVisitor.cpp:271:

-     explicit operator bool() const { return Kind_ != Kind::None; }
+     explicit operator bool() const { return m_Kind != Kind::None; }

lib/Differentiator/ReverseModeVisitor.cpp:277:

-       switch (Kind_) {
+       switch (m_Kind) {

lib/Differentiator/ReverseModeVisitor.cpp:291:

-       if (Kind_ != Kind::Realloc || Call_->getNumArgs() == 0)
+       if (m_Kind != Kind::Realloc || Call_->getNumArgs() == 0)

lib/Differentiator/ReverseModeVisitor.cpp:301:

-     AllocCallInfo(Kind k, clang::CallExpr* c) : Kind_(k), Call_(c) {}
-     Kind Kind_ = Kind::None;
+     AllocCallInfo(Kind k, clang::CallExpr* c) : m_Kind(k), Call_(c) {}
+     Kind m_Kind = Kind::None;

private:
AllocCallInfo(Kind k, clang::CallExpr* c) : Kind_(k), Call_(c) {}
Kind Kind_ = Kind::None;
clang::CallExpr* Call_ = 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: invalid case style for private member 'Call_' [readability-identifier-naming]

lib/Differentiator/ReverseModeVisitor.cpp:270:

-     clang::CallExpr* call() const { return Call_; }
+     clang::CallExpr* call() const { return m_Call; }

lib/Differentiator/ReverseModeVisitor.cpp:279:

-         return Call_->getArg(0);
+         return m_Call->getArg(0);

lib/Differentiator/ReverseModeVisitor.cpp:281:

-         return Call_->getArg(1);
+         return m_Call->getArg(1);

lib/Differentiator/ReverseModeVisitor.cpp:291:

-       if (Kind_ != Kind::Realloc || Call_->getNumArgs() == 0)
+       if (Kind_ != Kind::Realloc || m_Call->getNumArgs() == 0)

lib/Differentiator/ReverseModeVisitor.cpp:296:

-           Call_->getArg(0)->IgnoreParenCasts());
+           m_Call->getArg(0)->IgnoreParenCasts());

lib/Differentiator/ReverseModeVisitor.cpp:301:

-     AllocCallInfo(Kind k, clang::CallExpr* c) : Kind_(k), Call_(c) {}
+     AllocCallInfo(Kind k, clang::CallExpr* c) : Kind_(k), m_Call(c) {}
Suggested change
clang::CallExpr* Call_ = nullptr;
clang::CallExpr* m_Call = nullptr;

@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

return AllocCallInfo(k, CE);
}

Kind kind() const { return m_Kind; }

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: function 'kind' should be marked [[nodiscard]] [modernize-use-nodiscard]

Suggested change
Kind kind() const { return m_Kind; }
[[nodiscard]] Kind kind() const { return m_Kind; }

}

Kind kind() const { return m_Kind; }
clang::CallExpr* call() const { return m_Call; }

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: function 'call' should be marked [[nodiscard]] [modernize-use-nodiscard]

Suggested change
clang::CallExpr* call() const { return m_Call; }
[[nodiscard]] clang::CallExpr* call() const { return m_Call; }

@codecov

codecov Bot commented Jul 30, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.

📢 Thoughts on this report? Let us know!

Reverse mode recognised malloc/calloc/realloc by ad-hoc name-string
checks in two places: CheckAndBuildCallToMemset re-parsed the RHS for the
memset size, and the in-place-realloc test re-parsed it again for the
store/restore skip. The two walked the same call independently and are
easy to drift apart.

Introduce a small AllocCallInfo recognizer that classifies a heap-memory
builtin once and owns the per-op invariants -- the memset byte-size
operand (malloc arg0 / realloc arg1; calloc self-zeroes) and the in-place
realloc check (LHS is realloc's own pointer argument). Both sites now go
through it. No functional change: the growing realloc stays valgrind
clean and the shrinking case is unchanged.
@vgvassilev
vgvassilev merged commit 24a56e9 into master Jul 31, 2026
40 checks passed
@vgvassilev
vgvassilev deleted the refactor-allocs branch July 31, 2026 09:34
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