Skip to content

Commit 25a872c

Browse files
committed
Added some sanity checks to function call compilation. This will catch *some* cases of ABI mismatch.
1 parent 962a08f commit 25a872c

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
@@ -438,6 +438,10 @@ pub trait TypeReflection<'gcc, 'tcx> {
438438
fn is_u128(&self, cx: &CodegenCx<'gcc, 'tcx>) -> bool;
439439

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

443447
impl<'gcc, 'tcx> TypeReflection<'gcc, 'tcx> for Type<'gcc> {
@@ -537,4 +541,106 @@ impl<'gcc, 'tcx> TypeReflection<'gcc, 'tcx> for Type<'gcc> {
537541

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

0 commit comments

Comments
 (0)