Implement passing arguments by ref for win64 ABI

This commit is contained in:
teapotd
2020-05-25 20:34:50 +02:00
parent 94380bf2b7
commit 759cc3e751
6 changed files with 128 additions and 10 deletions

View File

@@ -54,6 +54,9 @@ pub enum ValueConversion {
/// Unsigned zero-extend value to the required type.
Uext(Type),
/// Pass value by pointer of given integer type.
Pointer(Type),
}
impl ValueConversion {
@@ -63,7 +66,7 @@ impl ValueConversion {
Self::IntSplit => ty.half_width().expect("Integer type too small to split"),
Self::VectorSplit => ty.half_vector().expect("Not a vector"),
Self::IntBits => Type::int(ty.bits()).expect("Bad integer size"),
Self::Sext(nty) | Self::Uext(nty) => nty,
Self::Sext(nty) | Self::Uext(nty) | Self::Pointer(nty) => nty,
}
}
@@ -74,6 +77,11 @@ impl ValueConversion {
_ => false,
}
}
/// Is this a conversion to pointer?
pub fn is_pointer(self) -> bool {
matches!(self, Self::Pointer(_))
}
}
/// Common trait for assigning arguments to registers or stack locations.
@@ -110,10 +118,16 @@ pub fn legalize_args<AA: ArgAssigner>(args: &[AbiParam], aa: &mut AA) -> Option<
}
// Split this argument into two smaller ones. Then revisit both.
ArgAction::Convert(conv) => {
debug_assert!(
!arg.legalized_to_pointer,
"No more conversions allowed after conversion to pointer"
);
let value_type = conv.apply(arg.value_type);
let new_arg = AbiParam { value_type, ..arg };
args.to_mut()[argno].value_type = value_type;
if conv.is_split() {
if conv.is_pointer() {
args.to_mut()[argno].legalized_to_pointer = true;
} else if conv.is_split() {
let new_arg = AbiParam { value_type, ..arg };
args.to_mut().insert(argno + 1, new_arg);
}
}
@@ -152,6 +166,10 @@ pub fn legalize_abi_value(have: Type, arg: &AbiParam) -> ValueConversion {
let have_bits = have.bits();
let arg_bits = arg.value_type.bits();
if arg.legalized_to_pointer {
return ValueConversion::Pointer(arg.value_type);
}
match have_bits.cmp(&arg_bits) {
// We have fewer bits than the ABI argument.
Ordering::Less => {
@@ -226,5 +244,12 @@ mod tests {
legalize_abi_value(types::F64, &arg),
ValueConversion::IntBits
);
// Value is passed by reference
arg.legalized_to_pointer = true;
assert_eq!(
legalize_abi_value(types::F64, &arg),
ValueConversion::Pointer(types::I32)
);
}
}