-
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?
Added some sanity checks to function call compilation. This will catch *some* cases of ABI mismatch. #715
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -425,6 +425,10 @@ pub trait TypeReflection<'gcc, 'tcx> { | |
fn is_u128(&self, cx: &CodegenCx<'gcc, 'tcx>) -> bool; | ||
|
||
fn is_vector(&self) -> bool; | ||
/// Checks if 2 types are "known to be equal". Returns Some(true) if types are equal(e.g. bool and bool), | ||
/// Some(false) if they can't possibly be equal(e.g. a struct and a float), and None if there is no way | ||
/// to check for their equality(struct and struct) | ||
fn known_eq(&self, rhs: &Self, cx: &CodegenCx<'gcc, 'tcx>) -> Option<bool>; | ||
} | ||
|
||
impl<'gcc, 'tcx> TypeReflection<'gcc, 'tcx> for Type<'gcc> { | ||
|
@@ -524,4 +528,106 @@ impl<'gcc, 'tcx> TypeReflection<'gcc, 'tcx> for Type<'gcc> { | |
|
||
false | ||
} | ||
fn known_eq(&self, other: &Self, cx: &CodegenCx<'gcc, 'tcx>) -> Option<bool> { | ||
// "Happy" path: types represented using the same pointer | ||
if self == other { | ||
return Some(true); | ||
} | ||
if self.is_bool() { | ||
return Some(other.is_bool()); | ||
} else if self.is_integral() { | ||
// Int and.. something? Not equal. | ||
if !other.is_integral() { | ||
return Some(false); | ||
} | ||
// Do the intigers have the same size and sign? | ||
return Some( | ||
(self.get_size() == other.get_size()) | ||
&& (self.is_signed(cx) == other.is_signed(cx)), | ||
); | ||
} else if self.is_vector() { | ||
// Vector and.. something? Different types. | ||
if !other.is_vector() { | ||
return Some(false); | ||
} | ||
// Both are vectors - try to get them directly | ||
let (Some(lhs), Some(rhs)) = (self.dyncast_vector(), other.dyncast_vector()) else { | ||
return None; | ||
}; | ||
// Different element count - different types. | ||
if lhs.get_num_units() != rhs.get_num_units() { | ||
return Some(false); | ||
} | ||
// Same element - same type. | ||
return lhs.get_element_type().known_eq(&rhs.get_element_type(), cx); | ||
} else if let Some(lhs) = self.is_struct() { | ||
// Struct and a not-struct? Different types. | ||
let Some(rhs) = other.is_struct() else { | ||
return Some(false); | ||
}; | ||
// Different *field count*? Different types. | ||
if lhs.get_field_count() != rhs.get_field_count() { | ||
return Some(false); | ||
} | ||
// We can't get the type of a filed quite yet. So, we will say that we don't know if the structs are equal. | ||
return None; | ||
} else if let Some(s_ptr) = self.get_pointee() { | ||
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 commentThe 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 commentThe 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 As we discussed before, comparing 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 commentThe 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. 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 commentThe reason will be displayed to describe this comment to others. Learn more. I still believe that using that using Also, I would be very wary of a struct comparison done like that: we need to take some attributes into account like There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Which is why Overall, the idea is for 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 commentThe reason will be displayed to describe this comment to others. Learn more. Also There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
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 commentThe reason will be displayed to describe this comment to others. Learn more.
Please tell me if a fix to libgccjit related to |
||
} else if let Some(lhs_elem) = self.dyncast_array() { | ||
// Array and not an array - not equal. | ||
let Some(rhs_elem) = other.dyncast_array() else { | ||
return Some(false); | ||
}; | ||
// Mismatched elements - not equal | ||
if !lhs_elem.known_eq(&rhs_elem, cx)? { | ||
return Some(false); | ||
} | ||
return None; | ||
} else if let Some(lhs_ptr) = self.dyncast_function_ptr_type() { | ||
// Fn ptr and not fn ptr - not equal. | ||
let Some(rhs_ptr) = other.dyncast_function_ptr_type() else { | ||
return Some(false); | ||
}; | ||
// Wrong argc | ||
if lhs_ptr.get_param_count() != rhs_ptr.get_param_count() { | ||
return Some(false); | ||
} | ||
// Wrong ret | ||
if !lhs_ptr.get_return_type().known_eq(&rhs_ptr.get_return_type(), cx)? { | ||
return Some(false); | ||
} | ||
// Wrong param count. | ||
for idx in 0..lhs_ptr.get_param_count() { | ||
if !lhs_ptr.get_param_type(idx).known_eq(&rhs_ptr.get_param_type(idx), cx)? { | ||
return Some(false); | ||
} | ||
} | ||
return None; | ||
} | ||
#[cfg(feature = "master")] | ||
if self.is_floating_point() { | ||
if !other.is_floating_point() { | ||
return Some(false); | ||
} | ||
return Some(self.get_size() == other.get_size()); | ||
} | ||
#[cfg(not(feature = "master"))] | ||
{ | ||
fn is_floating_point<'gcc>(ty: &Type<'gcc>, cx: &CodegenCx<'gcc, '_>) -> bool { | ||
ty.is_compatible_with(cx.context.new_type::<f32>()) | ||
|| ty.is_compatible_with(cx.context.new_type::<f64>()) | ||
} | ||
if is_floating_point(self, cx) { | ||
if !is_floating_point(self, cx) { | ||
return Some(false); | ||
} | ||
return Some(self.get_size() == other.get_size()); | ||
} | ||
} | ||
// Unknown type... | ||
None | ||
} | ||
} |
Uh oh!
There was an error while loading. Please reload this page.