Fix c_variadic flag and add opaque info to PassMode

We should expand the information in PassMode later.
This commit is contained in:
Celina G. Val 2023-12-19 11:04:34 -08:00
parent 1a83c5b55b
commit 76b3e6de55
3 changed files with 53 additions and 17 deletions

View File

@ -66,11 +66,14 @@ impl<'tcx> Stable<'tcx> for rustc_target::abi::call::FnAbi<'tcx, ty::Ty<'tcx>> {
type T = FnAbi; type T = FnAbi;
fn stable(&self, tables: &mut Tables<'tcx>) -> Self::T { fn stable(&self, tables: &mut Tables<'tcx>) -> Self::T {
assert!(self.args.len() >= self.fixed_count as usize);
assert!(!self.c_variadic || matches!(self.conv, Conv::C));
FnAbi { FnAbi {
args: self.args.as_ref().stable(tables), args: self.args.as_ref().stable(tables),
ret: self.ret.stable(tables), ret: self.ret.stable(tables),
fixed_count: self.fixed_count, fixed_count: self.fixed_count,
conv: self.conv.stable(tables), conv: self.conv.stable(tables),
c_variadic: self.c_variadic,
} }
} }
} }
@ -122,10 +125,20 @@ impl<'tcx> Stable<'tcx> for rustc_target::abi::call::PassMode {
fn stable(&self, _tables: &mut Tables<'tcx>) -> Self::T { fn stable(&self, _tables: &mut Tables<'tcx>) -> Self::T {
match self { match self {
rustc_target::abi::call::PassMode::Ignore => PassMode::Ignore, rustc_target::abi::call::PassMode::Ignore => PassMode::Ignore,
rustc_target::abi::call::PassMode::Direct(_) => PassMode::Direct, rustc_target::abi::call::PassMode::Direct(attr) => PassMode::Direct(opaque(attr)),
rustc_target::abi::call::PassMode::Pair(_, _) => PassMode::Pair, rustc_target::abi::call::PassMode::Pair(first, second) => {
rustc_target::abi::call::PassMode::Cast { .. } => PassMode::Cast, PassMode::Pair(opaque(first), opaque(second))
rustc_target::abi::call::PassMode::Indirect { .. } => PassMode::Indirect, }
rustc_target::abi::call::PassMode::Cast { pad_i32, cast } => {
PassMode::Cast { pad_i32: *pad_i32, cast: opaque(cast) }
}
rustc_target::abi::call::PassMode::Indirect { attrs, meta_attrs, on_stack } => {
PassMode::Indirect {
attrs: opaque(attrs),
meta_attrs: opaque(meta_attrs),
on_stack: *on_stack,
}
}
} }
} }
} }

View File

@ -21,12 +21,9 @@ pub struct FnAbi {
/// The ABI convention. /// The ABI convention.
pub conv: CallConvention, pub conv: CallConvention,
}
impl FnAbi { /// Whether this is a variadic C function,
pub fn is_c_variadic(&self) -> bool { pub c_variadic: bool,
self.args.len() > self.fixed_count as usize
}
} }
/// Information about the ABI of a function's argument, or return value. /// Information about the ABI of a function's argument, or return value.
@ -47,15 +44,15 @@ pub enum PassMode {
/// Pass the argument directly. /// Pass the argument directly.
/// ///
/// The argument has a layout abi of `Scalar` or `Vector`. /// The argument has a layout abi of `Scalar` or `Vector`.
Direct, Direct(Opaque),
/// Pass a pair's elements directly in two arguments. /// Pass a pair's elements directly in two arguments.
/// ///
/// The argument has a layout abi of `ScalarPair`. /// The argument has a layout abi of `ScalarPair`.
Pair, Pair(Opaque, Opaque),
/// Pass the argument after casting it. /// Pass the argument after casting it.
Cast, Cast { pad_i32: bool, cast: Opaque },
/// Pass the argument indirectly via a hidden pointer. /// Pass the argument indirectly via a hidden pointer.
Indirect, Indirect { attrs: Opaque, meta_attrs: Opaque, on_stack: bool },
} }
/// The layout of a type, alongside the type itself. /// The layout of a type, alongside the type itself.

View File

@ -23,7 +23,7 @@ use rustc_middle::ty::TyCtxt;
use rustc_smir::rustc_internal; use rustc_smir::rustc_internal;
use stable_mir::abi::{ArgAbi, CallConvention, FieldsShape, PassMode, VariantsShape}; use stable_mir::abi::{ArgAbi, CallConvention, FieldsShape, PassMode, VariantsShape};
use stable_mir::mir::mono::Instance; use stable_mir::mir::mono::Instance;
use stable_mir::{CrateDef, CrateItems, ItemKind}; use stable_mir::{CrateDef, CrateItem, CrateItems, ItemKind};
use std::assert_matches::assert_matches; use std::assert_matches::assert_matches;
use std::convert::TryFrom; use std::convert::TryFrom;
use std::io::Write; use std::io::Write;
@ -35,6 +35,8 @@ const CRATE_NAME: &str = "input";
fn test_stable_mir(_tcx: TyCtxt<'_>) -> ControlFlow<()> { fn test_stable_mir(_tcx: TyCtxt<'_>) -> ControlFlow<()> {
// Find items in the local crate. // Find items in the local crate.
let items = stable_mir::all_local_items(); let items = stable_mir::all_local_items();
// Test fn_abi
let target_fn = *get_item(&items, (ItemKind::Fn, "fn_abi")).unwrap(); let target_fn = *get_item(&items, (ItemKind::Fn, "fn_abi")).unwrap();
let instance = Instance::try_from(target_fn).unwrap(); let instance = Instance::try_from(target_fn).unwrap();
let fn_abi = instance.fn_abi().unwrap(); let fn_abi = instance.fn_abi().unwrap();
@ -45,9 +47,26 @@ fn test_stable_mir(_tcx: TyCtxt<'_>) -> ControlFlow<()> {
check_primitive(&fn_abi.args[1]); check_primitive(&fn_abi.args[1]);
check_result(fn_abi.ret); check_result(fn_abi.ret);
// Test variadic function.
let variadic_fn = *get_item(&items, (ItemKind::Fn, "variadic_fn")).unwrap();
check_variadic(variadic_fn);
ControlFlow::Continue(()) ControlFlow::Continue(())
} }
/// Check the variadic function ABI:
/// ```no_run
/// pub unsafe extern "C" fn variadic_fn(n: usize, mut args: ...) -> usize {
/// 0
/// }
/// ```
fn check_variadic(variadic_fn: CrateItem) {
let instance = Instance::try_from(variadic_fn).unwrap();
let abi = instance.fn_abi().unwrap();
assert!(abi.c_variadic);
assert_eq!(abi.args.len(), 1);
}
/// Check the argument to be ignored: `ignore: [u8; 0]`. /// Check the argument to be ignored: `ignore: [u8; 0]`.
fn check_ignore(abi: &ArgAbi) { fn check_ignore(abi: &ArgAbi) {
assert!(abi.ty.kind().is_array()); assert!(abi.ty.kind().is_array());
@ -60,7 +79,7 @@ fn check_ignore(abi: &ArgAbi) {
/// Check the primitive argument: `primitive: char`. /// Check the primitive argument: `primitive: char`.
fn check_primitive(abi: &ArgAbi) { fn check_primitive(abi: &ArgAbi) {
assert!(abi.ty.kind().is_char()); assert!(abi.ty.kind().is_char());
assert_eq!(abi.mode, PassMode::Direct); assert_matches!(abi.mode, PassMode::Direct(_));
let layout = abi.layout.shape(); let layout = abi.layout.shape();
assert!(layout.is_sized()); assert!(layout.is_sized());
assert!(!layout.is_1zst()); assert!(!layout.is_1zst());
@ -70,7 +89,7 @@ fn check_primitive(abi: &ArgAbi) {
/// Check the return value: `Result<usize, &str>`. /// Check the return value: `Result<usize, &str>`.
fn check_result(abi: ArgAbi) { fn check_result(abi: ArgAbi) {
assert!(abi.ty.kind().is_enum()); assert!(abi.ty.kind().is_enum());
assert_eq!(abi.mode, PassMode::Indirect); assert_matches!(abi.mode, PassMode::Indirect { .. });
let layout = abi.layout.shape(); let layout = abi.layout.shape();
assert!(layout.is_sized()); assert!(layout.is_sized());
assert_matches!(layout.fields, FieldsShape::Arbitrary { .. }); assert_matches!(layout.fields, FieldsShape::Arbitrary { .. });
@ -106,11 +125,18 @@ fn generate_input(path: &str) -> std::io::Result<()> {
write!( write!(
file, file,
r#" r#"
#[allow(unused_variables)] #![feature(c_variadic)]
#![allow(unused_variables)]
pub fn fn_abi(ignore: [u8; 0], primitive: char) -> Result<usize, &'static str> {{ pub fn fn_abi(ignore: [u8; 0], primitive: char) -> Result<usize, &'static str> {{
// We only care about the signature. // We only care about the signature.
todo!() todo!()
}} }}
pub unsafe extern "C" fn variadic_fn(n: usize, mut args: ...) -> usize {{
0
}}
"# "#
)?; )?;
Ok(()) Ok(())