-
Notifications
You must be signed in to change notification settings - Fork 123
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Initial support for memory operations in reverse mode #777
Conversation
Codecov ReportAttention: Patch coverage is
Additional details and impacted files@@ Coverage Diff @@
## master #777 +/- ##
==========================================
+ Coverage 94.71% 94.78% +0.06%
==========================================
Files 49 49
Lines 7342 7477 +135
==========================================
+ Hits 6954 7087 +133
- Misses 388 390 +2
... and 1 file with indirect coverage changes
|
There was a problem hiding this comment.
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
@@ -41,6 +41,8 @@ namespace clad { | |||
/// the reverse mode we also accumulate Stmts for the reverse pass which | |||
/// will be executed on return. | |||
std::vector<Stmts> m_Reverse; | |||
/// Storing expressions to delete/free memory in the reverse pass. | |||
Stmts m_DeallocExprs; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
warning: member variable 'm_DeallocExprs' has protected visibility [cppcoreguidelines-non-private-member-variables-in-classes]
Stmts m_DeallocExprs;
^
This seems to be a good start. I think the solution needs some refinements to work for all cases. The differentiation of the below code fails with the error: double fn(double u, double v) {
double *nu = new double(u);
double res = 2 * *nu;
delete nu;
nu = new double(v);
res = 2 * *nu;
delete nu;
return res;
}
int main() {
auto fn_grad = clad::gradient(fn);
double u = 3, v = 5, du = 0, dv = 0;
fn_grad.execute(u, v, &du, &dv);
} The current solution is also not equipped to handle double identity(double *p) {
double v = *p;
delete p;
return v;
}
double fn(double u, double v) {
double *nu = new double(u);
double res = 2 * identity(nu);
double *nv = new double(v);
res += 2 * *nv;
delete nv;
return res;
}
int main() {
auto fn_grad = clad::gradient(fn);
double u = 3, v = 5, du = 0, dv = 0;
fn_grad.execute(u, v, &du, &dv);
} The differentiation of this code fails because the derivative pointer would be deleted prematurely in |
@parth-07 Agreed, this is in no way a perfect solution, but meant as a fix for preventing clad from crashing on |
Is there a way to diagnose the unsupported cases? |
Iteratively adding features when they are required is of course the preferred way. However, we should have an idea on how to support the missing features, otherwise, later on, we may need to change the initial groundwork.
Yes, the first case is easier to resolve. But the second case,
If the goal for now is simply to prevent clad from crashing. Then perhaps we can simply ignore the |
One possibility is to show a warning on every delete stmt, something like: |
I think it is better to support it minimally than to not support it at all. I don't see a way of how the analysis of such complex cases will look (even for cases like for loops or if conditions), but even if we have to remove the work in this commit entirely for a better solution in future, I don't see that as an issue. |
fee1a93
to
dbcf6f7
Compare
There was a problem hiding this comment.
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
There was a problem hiding this comment.
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
There were too many comments to post at once. Showing the first 10 out of 16. Check the log or trigger a new build to see more.
a1f9cd2
to
b9f8f31
Compare
There was a problem hiding this comment.
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
8f0a34e
to
af639a0
Compare
We will be able to support the differentiation of functions that use
Yes, it's not a big issue. However, I believe more effort will be required in this way. I was just giving my two cents. Please continue with the approach that you find best. |
Ah, I misunderstood the ignoring delete statements part, thanks for clarifying. I guess we should let the user have some options to choose from here, some users would prefer one over the other depending on their applications. |
There was a problem hiding this comment.
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
lib/Differentiator/CladUtils.cpp
Outdated
} | ||
|
||
bool IsMemoryDeallocationFunction(const clang::FunctionDecl* FD) { | ||
return FD->getBuiltinID() == Builtin::BIfree; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
warning: no member named 'BIfree' in namespace 'clang::Builtin' [clang-diagnostic-error]
return FD->getBuiltinID() == Builtin::BIfree;
^
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks like this was introduced in llvm/llvm-project@7119f76 which is available on clang 15 onward...
EDIT: This is incorrect. That builtin has been there since clang 7 see (llvm/llvm-project@5ecdb944).
Another edit: looks like the BIfree
is added in llvm/llvm-project@425a83a5. I guess we need to make sure we have the right ifdef-s so that once we move to more recent versions of the minimal version of supported clang everything becomes uniform.
I was wondering if we could emit the delete statements when the allocation is in the function we differentiate and produce a warning if the allocation/deallocation is across function boundaries? |
But, there are many cases where even if the delete(s) are in the same function, the current implementation will output wrong statements, for ex. - multiple new and delete combinations (as exemplified by Parth), delete(s) inside for/if conditions and maybe many more. |
There was a problem hiding this comment.
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
89e3fde
to
9c1f4a1
Compare
Turns out there was some issue when zero initializing a newly created array using |
There was a problem hiding this comment.
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
11c8e73
to
05b2684
Compare
All tests are passing finally 🎉 |
// CHECK-NEXT: t->i = i; | ||
// CHECK-NEXT: double _d_res = *_d_p + _d_t->i; | ||
// CHECK-NEXT: double res = *p + t->i; | ||
// CHECK-NEXT: unsigned {{(int|long)}} _t2 = sizeof(double); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I was wondering why we are not writing out size_t
here?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
not sure about this
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ok, let's discuss that issue separately.
@parth-07 and I chatted a little and we'd like to move forward. Once we get some more experience then we should decide if we want to relax the delete operations in favor of more memory leaks. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM!
This does not add complete support for
new
anddelete
operators, there are many examples that can be constructed which will fail or crash. However, it covers the mostly-used case of allocating memory in the beginning and deallocating in the end.Edit: Also, added C-style memory alloc and
free
operations.fixes #654