-
Notifications
You must be signed in to change notification settings - Fork 78
Added some sanity checks to function call compilation. This will catch *some* cases of ABI mismatch. #715
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
base: master
Are you sure you want to change the base?
Conversation
6c97dd7
to
f14745c
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.
Some questions.
src/common.rs
Outdated
if !other.is_vector() { | ||
return Some(false); | ||
} | ||
return None; |
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.
Do you think it would be worth it to check the sizes match?
We can probably do it with get_element_type()
and get_num_units()
?
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.
Might be worth checking. Will add now.
let Some(other_ptr) = other.get_pointee() else { | ||
return Some(false); | ||
}; | ||
return s_ptr.known_eq(&other_ptr, cx); |
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 guess it doesn't matter much since there's a check for pointers in the assert in the other file, but is this the expected behavior to check if the pointee types are equal since we can bitcast pointers of different types?
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.
The code path calling this funcition in the assert should not be hit by pointers at all - it is meant to bitcast vectors.
The idea behind known_eq
is to serve as a saner replacement for the current Eq
implementation of Type
.
As we discussed before, comparing Types
/ Rvalues
on the libgccjit
side is quite hard to do, and would require a lot of code to be added.
Here, I am seeing if I could possibly work around that issue, by doing some of that comparison logic on the Rust side.
Really, I am trying to see if I could implement the functions we require entirely on the Rust side, subverting the limitations of the GCC API.
One thing I am considering attempting is field-vise comparison of structs(so that structs with identical elements compare as equal).
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.
This could be quite useful for our constant deduplication code. Since my last attempt at fixing that leak introduces non-determinism to the compiler, we will have to revert and replace that.
At one point, I suggested we compare the types of Rvalues before comparing them using string formatting.
I was told that will not work because we can't reliably compare types. known_eq
solves that problem(once I get struct comparisons working). If 2 rvalues have different types, we know they can't be equal, so we don't do the string-based comparison.
I belive this would remove most of that memory leak in a sound and reliable way. I have other ways to aleviate that issue, but this will be the most impactfull.
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 still believe that using that using global_set_initializer()
would be better than this approach. Was there any reason it would not work?
Also, I would be very wary of a struct comparison done like that: we need to take some attributes into account like packed
and possibly some others: I much prefer to let that job to the gcc backend even though I'm not sure right now how that could work since it would involve the target part of the compiler.
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.
global_set_initializer
(and globlal_set_initialized_rvalue
) required globals to have unique names, and I think that messed with the string-based comparisons. I also belive could not get it to ever run right - global_set_initializer
always errored out when I used it. I belive that was caused by some kind of type issue - it always complained about the type of the global and the type of the initializer rvalue being different. Maybe this is related to us calling get_aligned
needlessly.
Also, I would be very wary of a struct comparison done like that: we need to take some attributes into account like packed and possibly some others: I much prefer to let that job to the gcc backend even though I'm not sure right now how that could work since it would involve the target part of the compiler.
Which is why known_eq
will not return Some(true)
for structs(at least for now). For structs, the current version only allows us to check that structs are unequal which is fine for our purposes.
Overall, the idea is for known_eq
to return Some(true)
if and only if the types are guaranteed to be equal, and return Some(false)
if we can show that they are not equal.
For the global de-duplication, this comparison is simply an optimization. All it does skip the more costly comparison if we know for sure it will return false.
Additionally, for our purposes, catching most of the cases where types are not equal is already good enough.
If a sanity check can catch 99.9% of issues early, then it is worth it in my book.
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.
Also global_set_initializer
will not help us with deduplication, at all. We will still have to manage the lvalues by ourselves, and deduplicate them ourselves.
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.
Also
global_set_initializer
will not help us with deduplication, at all.
Oh, sorry: I was mixing things up with the reduction of the memory usage.
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.
global_set_initializer
(andgloblal_set_initialized_rvalue
) required globals to have unique names, and I think that messed with the string-based comparisons. I also belive could not get it to ever run right -global_set_initializer
always errored out when I used it. I belive that was caused by some kind of type issue - it always complained about the type of the global and the type of the initializer rvalue being different. Maybe this is related to us callingget_aligned
needlessly.
Please tell me if a fix to libgccjit related to global_set_initializer
would help you with your fix the reduce the memory usage (e.g. remove the non-determinism). I could take a look.
…h *some* cases of ABI mismatch.
This PR introduces 2 changes:
The function
known_eq
is a fallible form of equality.known_eq
does not suffer from the issues the current implementation ofEq
suffers from(sometimes, afloat
would be compared as uneqal tofloat
simply because the pointer was different).known_eq
reimplements some of that logic by itself, returning Some(true) if and only if types are known to be equal, and Some(false) if and only if it is known that the types can't be possibly equal.This is later used in a sanity check in
Builder::check_ptr_call
. Instead of checking if both types are / are not vectors, it will check if they are "known to be unequal". So, it will also painc if this code path is taken with types struct and pointer(ABI mismatch) but will still allow primitive types to pass trough. Since we only panic if the types are not vectors, and are known to be uneqal, this will effectively only catch ABI issues.This change allows us to catch ABI bugs like #711 on the
cg_gcc
side, giving us a proper backtrace, and more detalied information about the bug(the types in play, the argument), and allowing us to use a debuger to see exactly what went wrong.