Skip to content

Commit aa060fb

Browse files
committed
Added some sanity checks to function call compilation. This will catch *some* cases of ABI mismatch.
1 parent ac500d4 commit aa060fb

File tree

2 files changed

+110
-11
lines changed

2 files changed

+110
-11
lines changed

src/builder.rs

Lines changed: 4 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -270,18 +270,11 @@ impl<'a, 'gcc, 'tcx> Builder<'a, 'gcc, 'tcx> {
270270
actual_val.dereference(self.location).to_rvalue()
271271
}
272272
} else {
273-
// FIXME: this condition seems wrong: it will pass when both types are not
274-
// a vector.
273+
// Check that the types are not "known to mismatch" or are vectors
275274
assert!(
276-
(!expected_ty.is_vector() || actual_ty.is_vector())
277-
&& (expected_ty.is_vector() || !actual_ty.is_vector()),
278-
"{:?} (is vector: {}) -> {:?} (is vector: {}), Function: {:?}[{}]",
279-
actual_ty,
280-
actual_ty.is_vector(),
281-
expected_ty,
282-
expected_ty.is_vector(),
283-
func_ptr,
284-
index
275+
expected_ty.known_eq(&actual_ty, self.cx).unwrap_or(true)
276+
|| expected_ty.is_vector() && actual_ty.is_vector(),
277+
"{actual_ty:?} -> {expected_ty:?}, Function: {func_ptr:?}[{index}]"
285278
);
286279
// TODO(antoyo): perhaps use __builtin_convertvector for vector casting.
287280
// TODO: remove bitcast now that vector types can be compared?

src/common.rs

Lines changed: 106 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -425,6 +425,10 @@ pub trait TypeReflection<'gcc, 'tcx> {
425425
fn is_u128(&self, cx: &CodegenCx<'gcc, 'tcx>) -> bool;
426426

427427
fn is_vector(&self) -> bool;
428+
/// Checks if 2 types are "known to be equal". Returns Some(true) if types are equal(e.g. bool and bool),
429+
/// Some(false) if they can't possibly be equal(e.g. a struct and a float), and None if there is no way
430+
/// to check for their equality(struct and struct)
431+
fn known_eq(&self, rhs: &Self, cx: &CodegenCx<'gcc, 'tcx>) -> Option<bool>;
428432
}
429433

430434
impl<'gcc, 'tcx> TypeReflection<'gcc, 'tcx> for Type<'gcc> {
@@ -524,4 +528,106 @@ impl<'gcc, 'tcx> TypeReflection<'gcc, 'tcx> for Type<'gcc> {
524528

525529
false
526530
}
531+
fn known_eq(&self, other: &Self, cx: &CodegenCx<'gcc, 'tcx>) -> Option<bool> {
532+
// "Happy" path: types represented using the same pointer
533+
if self == other {
534+
return Some(true);
535+
}
536+
if self.is_bool() {
537+
return Some(other.is_bool());
538+
} else if self.is_integral() {
539+
// Int and.. something? Not equal.
540+
if !other.is_integral() {
541+
return Some(false);
542+
}
543+
// Do the intigers have the same size and sign?
544+
return Some(
545+
(self.get_size() == other.get_size())
546+
&& (self.is_signed(cx) == other.is_signed(cx)),
547+
);
548+
} else if self.is_vector() {
549+
// Vector and.. something? Different types.
550+
if !other.is_vector() {
551+
return Some(false);
552+
}
553+
// Both are vectors - try to get them directly
554+
let (Some(lhs), Some(rhs)) = (self.dyncast_vector(), other.dyncast_vector()) else {
555+
return None;
556+
};
557+
// Different element count - different types.
558+
if lhs.get_num_units() != rhs.get_num_units() {
559+
return Some(false);
560+
}
561+
// Same element - same type.
562+
return lhs.get_element_type().known_eq(&rhs.get_element_type(), cx);
563+
} else if let Some(lhs) = self.is_struct() {
564+
// Struct and a not-struct? Different types.
565+
let Some(rhs) = other.is_struct() else {
566+
return Some(false);
567+
};
568+
// Different *field count*? Different types.
569+
if lhs.get_field_count() != rhs.get_field_count() {
570+
return Some(false);
571+
}
572+
// 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.
573+
return None;
574+
} else if let Some(s_ptr) = self.get_pointee() {
575+
let Some(other_ptr) = other.get_pointee() else {
576+
return Some(false);
577+
};
578+
return s_ptr.known_eq(&other_ptr, cx);
579+
} else if let Some(lhs_elem) = self.dyncast_array() {
580+
// Array and not an array - not equal.
581+
let Some(rhs_elem) = other.dyncast_array() else {
582+
return Some(false);
583+
};
584+
// Mismatched elements - not equal
585+
if !lhs_elem.known_eq(&rhs_elem, cx)? {
586+
return Some(false);
587+
}
588+
return None;
589+
} else if let Some(lhs_ptr) = self.dyncast_function_ptr_type() {
590+
// Fn ptr and not fn ptr - not equal.
591+
let Some(rhs_ptr) = other.dyncast_function_ptr_type() else {
592+
return Some(false);
593+
};
594+
// Wrong argc
595+
if lhs_ptr.get_param_count() != rhs_ptr.get_param_count() {
596+
return Some(false);
597+
}
598+
// Wrong ret
599+
if !lhs_ptr.get_return_type().known_eq(&rhs_ptr.get_return_type(), cx)? {
600+
return Some(false);
601+
}
602+
// Wrong param count.
603+
for idx in 0..lhs_ptr.get_param_count() {
604+
if !lhs_ptr.get_param_type(idx).known_eq(&rhs_ptr.get_param_type(idx), cx)? {
605+
return Some(false);
606+
}
607+
}
608+
return None;
609+
}
610+
#[cfg(feature = "master")]
611+
if self.is_floating_point() {
612+
if !other.is_floating_point() {
613+
return Some(false);
614+
}
615+
return Some(self.get_size() == other.get_size());
616+
}
617+
#[cfg(not(feature = "master"))]
618+
{
619+
fn is_floating_point<'gcc>(ty: &Type<'gcc>, cx: &CodegenCx<'gcc, '_>) -> bool {
620+
ty.is_compatible_with(cx.context.new_type::<f32>())
621+
|| ty.is_compatible_with(cx.context.new_type::<f64>())
622+
}
623+
if is_floating_point(self, cx) {
624+
if !is_floating_point(self, cx) {
625+
return Some(false);
626+
}
627+
return Some(self.get_size() == other.get_size());
628+
}
629+
}
630+
// Unknown type...
631+
None
632+
}
527633
}

0 commit comments

Comments
 (0)