diff --git a/src/builder.rs b/src/builder.rs index 2c5ae3fff7b..dcc7a020a64 100644 --- a/src/builder.rs +++ b/src/builder.rs @@ -270,18 +270,11 @@ impl<'a, 'gcc, 'tcx> Builder<'a, 'gcc, 'tcx> { actual_val.dereference(self.location).to_rvalue() } } else { - // FIXME: this condition seems wrong: it will pass when both types are not - // a vector. + // Check that the types are not "known to mismatch" or are vectors assert!( - (!expected_ty.is_vector() || actual_ty.is_vector()) - && (expected_ty.is_vector() || !actual_ty.is_vector()), - "{:?} (is vector: {}) -> {:?} (is vector: {}), Function: {:?}[{}]", - actual_ty, - actual_ty.is_vector(), - expected_ty, - expected_ty.is_vector(), - func_ptr, - index + expected_ty.known_eq(&actual_ty, self.cx).unwrap_or(true) + || expected_ty.is_vector() && actual_ty.is_vector(), + "{actual_ty:?} -> {expected_ty:?}, Function: {func_ptr:?}[{index}]" ); // TODO(antoyo): perhaps use __builtin_convertvector for vector casting. // TODO: remove bitcast now that vector types can be compared? diff --git a/src/common.rs b/src/common.rs index 58ff2f1f8f0..396a0576949 100644 --- a/src/common.rs +++ b/src/common.rs @@ -438,6 +438,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; } impl<'gcc, 'tcx> TypeReflection<'gcc, 'tcx> for Type<'gcc> { @@ -537,4 +541,106 @@ impl<'gcc, 'tcx> TypeReflection<'gcc, 'tcx> for Type<'gcc> { false } + fn known_eq(&self, other: &Self, cx: &CodegenCx<'gcc, 'tcx>) -> Option { + // "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); + } 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::()) + || ty.is_compatible_with(cx.context.new_type::()) + } + 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 + } }