Auto merge of #141942 - ShoyuVanilla:smir-repr, r=oli-obk

Implement representation options to smir

Resolves rust-lang/project-stable-mir#89
This commit is contained in:
bors 2025-06-11 07:45:07 +00:00
commit 0a39445252
6 changed files with 132 additions and 6 deletions

View file

@ -16,7 +16,7 @@ use rustc_middle::ty::{
};
use rustc_middle::{mir, ty};
use rustc_span::def_id::LOCAL_CRATE;
use stable_mir::abi::{FnAbi, Layout, LayoutShape};
use stable_mir::abi::{FnAbi, Layout, LayoutShape, ReprOptions};
use stable_mir::mir::alloc::GlobalAlloc;
use stable_mir::mir::mono::{InstanceDef, StaticDef};
use stable_mir::mir::{BinOp, Body, Place, UnOp};
@ -397,6 +397,13 @@ impl<'tcx> SmirCtxt<'tcx> {
tables.tcx.is_lang_item(def_id, LangItem::CStr)
}
/// Returns the representation options for this ADT
pub fn adt_repr(&self, def: AdtDef) -> ReprOptions {
let mut tables = self.0.borrow_mut();
let tcx = tables.tcx;
def.internal(&mut *tables, tcx).repr().stable(&mut *tables)
}
/// Retrieve the function signature for the given generic arguments.
pub fn fn_sig(&self, def: FnDef, args: &GenericArgs) -> PolyFnSig {
let mut tables = self.0.borrow_mut();

View file

@ -6,9 +6,9 @@ use rustc_abi::{ArmCall, CanonAbi, InterruptKind, X86Call};
use rustc_middle::ty;
use rustc_target::callconv;
use stable_mir::abi::{
AddressSpace, ArgAbi, CallConvention, FieldsShape, FloatLength, FnAbi, IntegerLength, Layout,
LayoutShape, PassMode, Primitive, Scalar, TagEncoding, TyAndLayout, ValueAbi, VariantsShape,
WrappingRange,
AddressSpace, ArgAbi, CallConvention, FieldsShape, FloatLength, FnAbi, IntegerLength,
IntegerType, Layout, LayoutShape, PassMode, Primitive, ReprFlags, ReprOptions, Scalar,
TagEncoding, TyAndLayout, ValueAbi, VariantsShape, WrappingRange,
};
use stable_mir::opaque;
use stable_mir::target::MachineSize as Size;
@ -310,3 +310,42 @@ impl<'tcx> Stable<'tcx> for rustc_abi::WrappingRange {
WrappingRange { start: self.start, end: self.end }
}
}
impl<'tcx> Stable<'tcx> for rustc_abi::ReprFlags {
type T = ReprFlags;
fn stable(&self, _tables: &mut Tables<'_>) -> Self::T {
ReprFlags {
is_simd: self.intersects(Self::IS_SIMD),
is_c: self.intersects(Self::IS_C),
is_transparent: self.intersects(Self::IS_TRANSPARENT),
is_linear: self.intersects(Self::IS_LINEAR),
}
}
}
impl<'tcx> Stable<'tcx> for rustc_abi::IntegerType {
type T = IntegerType;
fn stable(&self, tables: &mut Tables<'_>) -> Self::T {
match self {
rustc_abi::IntegerType::Pointer(signed) => IntegerType::Pointer { is_signed: *signed },
rustc_abi::IntegerType::Fixed(integer, signed) => {
IntegerType::Fixed { length: integer.stable(tables), is_signed: *signed }
}
}
}
}
impl<'tcx> Stable<'tcx> for rustc_abi::ReprOptions {
type T = ReprOptions;
fn stable(&self, tables: &mut Tables<'_>) -> Self::T {
ReprOptions {
int: self.int.map(|int| int.stable(tables)),
align: self.align.map(|align| align.stable(tables)),
pack: self.pack.map(|pack| pack.stable(tables)),
flags: self.flags.stable(tables),
}
}
}

View file

@ -455,3 +455,38 @@ pub enum CallConvention {
RiscvInterrupt,
}
#[non_exhaustive]
#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug, Serialize)]
pub struct ReprFlags {
pub is_simd: bool,
pub is_c: bool,
pub is_transparent: bool,
pub is_linear: bool,
}
#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug, Serialize)]
pub enum IntegerType {
/// Pointer-sized integer type, i.e. `isize` and `usize`.
Pointer {
/// Signedness. e.g. `true` for `isize`
is_signed: bool,
},
/// Fixed-sized integer type, e.g. `i8`, `u32`, `i128`.
Fixed {
/// Length of this integer type. e.g. `IntegerLength::I8` for `u8`.
length: IntegerLength,
/// Signedness. e.g. `false` for `u8`
is_signed: bool,
},
}
/// Representation options provided by the user
#[non_exhaustive]
#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug, Serialize)]
pub struct ReprOptions {
pub int: Option<IntegerType>,
pub align: Option<Align>,
pub pack: Option<Align>,
pub flags: ReprFlags,
}

View file

@ -6,7 +6,7 @@
use std::cell::Cell;
use rustc_smir::context::SmirCtxt;
use stable_mir::abi::{FnAbi, Layout, LayoutShape};
use stable_mir::abi::{FnAbi, Layout, LayoutShape, ReprOptions};
use stable_mir::crate_def::Attribute;
use stable_mir::mir::alloc::{AllocId, GlobalAlloc};
use stable_mir::mir::mono::{Instance, InstanceDef, StaticDef};
@ -200,6 +200,11 @@ impl<'tcx> SmirInterface<'tcx> {
self.cx.adt_is_cstr(def)
}
/// Returns the representation options for this ADT
pub(crate) fn adt_repr(&self, def: AdtDef) -> ReprOptions {
self.cx.adt_repr(def)
}
/// Retrieve the function signature for the given generic arguments.
pub(crate) fn fn_sig(&self, def: FnDef, args: &GenericArgs) -> PolyFnSig {
self.cx.fn_sig(def, args)

View file

@ -9,6 +9,7 @@ use stable_mir::mir::mono::StaticDef;
use stable_mir::target::MachineInfo;
use stable_mir::{Filename, Opaque};
use super::abi::ReprOptions;
use super::mir::{Body, Mutability, Safety};
use super::{DefId, Error, Symbol, with};
use crate::stable_mir;
@ -818,6 +819,10 @@ impl AdtDef {
pub fn variant(&self, idx: VariantIdx) -> Option<VariantDef> {
(idx.to_index() < self.num_variants()).then_some(VariantDef { idx, adt_def: *self })
}
pub fn repr(&self) -> ReprOptions {
with(|cx| cx.adt_repr(*self))
}
}
/// Definition of a variant, which can be either a struct / union field or an enum variant.

View file

@ -21,10 +21,13 @@ use stable_mir::abi::{
ArgAbi, CallConvention, FieldsShape, IntegerLength, PassMode, Primitive, Scalar, ValueAbi,
VariantsShape,
};
use stable_mir::mir::MirVisitor;
use stable_mir::mir::mono::Instance;
use stable_mir::target::MachineInfo;
use stable_mir::ty::{AdtDef, RigidTy, Ty, TyKind};
use stable_mir::{CrateDef, CrateItem, CrateItems, ItemKind};
use std::assert_matches::assert_matches;
use std::collections::HashSet;
use std::convert::TryFrom;
use std::io::Write;
use std::ops::ControlFlow;
@ -67,6 +70,17 @@ fn test_stable_mir() -> ControlFlow<()> {
assert!(ptr_variadic_fn_abi.c_variadic);
assert_eq!(ptr_variadic_fn_abi.args.len(), 1);
let entry = stable_mir::entry_fn().unwrap();
let main_fn = Instance::try_from(entry).unwrap();
let mut visitor = AdtDefVisitor::default();
visitor.visit_body(&main_fn.body().unwrap());
let AdtDefVisitor { adt_defs } = visitor;
assert_eq!(adt_defs.len(), 1);
// Test ADT representation options
let repr_c_struct = adt_defs.iter().find(|def| def.trimmed_name() == "ReprCStruct").unwrap();
assert!(repr_c_struct.repr().flags.is_c);
ControlFlow::Continue(())
}
@ -138,6 +152,20 @@ fn get_item<'a>(
items.iter().find(|crate_item| (item.0 == crate_item.kind()) && crate_item.name() == item.1)
}
#[derive(Default)]
struct AdtDefVisitor {
adt_defs: HashSet<AdtDef>,
}
impl MirVisitor for AdtDefVisitor {
fn visit_ty(&mut self, ty: &Ty, _location: stable_mir::mir::visit::Location) {
if let TyKind::RigidTy(RigidTy::Adt(adt, _)) = ty.kind() {
self.adt_defs.insert(adt);
}
self.super_ty(ty)
}
}
/// This test will generate and analyze a dummy crate using the stable mir.
/// For that, it will first write the dummy crate into a file.
/// Then it will create a `StableMir` using custom arguments and then
@ -147,7 +175,7 @@ fn main() {
generate_input(&path).unwrap();
let args = &[
"rustc".to_string(),
"--crate-type=lib".to_string(),
"-Cpanic=abort".to_string(),
"--crate-name".to_string(),
CRATE_NAME.to_string(),
path.to_string(),
@ -185,6 +213,13 @@ fn generate_input(path: &str) -> std::io::Result<()> {
// We only care about the signature.
todo!()
}}
fn main() {{
#[repr(C)]
struct ReprCStruct;
let _s = ReprCStruct;
}}
"#
)?;
Ok(())