Skip to content
This repository was archived by the owner on May 28, 2025. It is now read-only.
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.

Commit 4c2c461

Browse files
authoredDec 20, 2023
Unrolled build for rust-lang#119094
Rollup merge of rust-lang#119094 - celinval:smir-layout, r=compiler-errors Add function ABI and type layout to StableMIR This change introduces a new module to StableMIR named `abi` with information from `rustc_target::abi` and `rustc_abi`, that allow users to retrieve more low level information required to perform bit-precise analysis. The layout of a type can be retrieved via `Ty::layout`, and the instance ABI can be retrieved via `Instance::fn_abi()`. To properly handle errors while retrieve layout information, we had to implement a few layout related traits. r? ```@compiler-errors```
2 parents 3095d31 + 76b3e6d commit 4c2c461

File tree

14 files changed

+796
-25
lines changed

14 files changed

+796
-25
lines changed
 

‎compiler/rustc_smir/src/rustc_internal/internal.rs

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
use crate::rustc_smir::Tables;
88
use rustc_middle::ty::{self as rustc_ty, Ty as InternalTy};
99
use rustc_span::Symbol;
10+
use stable_mir::abi::Layout;
1011
use stable_mir::mir::alloc::AllocId;
1112
use stable_mir::mir::mono::{Instance, MonoItem, StaticDef};
1213
use stable_mir::mir::{Mutability, Safety};
@@ -460,6 +461,14 @@ impl<'tcx> RustcInternal<'tcx> for Span {
460461
}
461462
}
462463

464+
impl<'tcx> RustcInternal<'tcx> for Layout {
465+
type T = rustc_target::abi::Layout<'tcx>;
466+
467+
fn internal(&self, tables: &mut Tables<'tcx>) -> Self::T {
468+
tables.layouts[*self]
469+
}
470+
}
471+
463472
impl<'tcx, T> RustcInternal<'tcx> for &T
464473
where
465474
T: RustcInternal<'tcx>,

‎compiler/rustc_smir/src/rustc_internal/mod.rs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ use rustc_middle::ty::TyCtxt;
1212
use rustc_span::def_id::{CrateNum, DefId};
1313
use rustc_span::Span;
1414
use scoped_tls::scoped_thread_local;
15+
use stable_mir::abi::Layout;
1516
use stable_mir::ty::IndexedVal;
1617
use stable_mir::Error;
1718
use std::cell::Cell;
@@ -136,6 +137,10 @@ impl<'tcx> Tables<'tcx> {
136137
pub(crate) fn static_def(&mut self, did: DefId) -> stable_mir::mir::mono::StaticDef {
137138
stable_mir::mir::mono::StaticDef(self.create_def_id(did))
138139
}
140+
141+
pub(crate) fn layout_id(&mut self, layout: rustc_target::abi::Layout<'tcx>) -> Layout {
142+
self.layouts.create_or_fetch(layout)
143+
}
139144
}
140145

141146
pub fn crate_num(item: &stable_mir::Crate) -> CrateNum {
@@ -180,6 +185,7 @@ where
180185
types: IndexMap::default(),
181186
instances: IndexMap::default(),
182187
constants: IndexMap::default(),
188+
layouts: IndexMap::default(),
183189
}));
184190
stable_mir::compiler_interface::run(&tables, || init(&tables, f))
185191
}

‎compiler/rustc_smir/src/rustc_smir/context.rs

Lines changed: 73 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,12 +3,19 @@
33
//! This trait is currently the main interface between the Rust compiler,
44
//! and the `stable_mir` crate.
55
6+
#![allow(rustc::usage_of_qualified_ty)]
7+
8+
use rustc_abi::HasDataLayout;
69
use rustc_middle::ty;
10+
use rustc_middle::ty::layout::{
11+
FnAbiOf, FnAbiOfHelpers, HasParamEnv, HasTyCtxt, LayoutOf, LayoutOfHelpers,
12+
};
713
use rustc_middle::ty::print::{with_forced_trimmed_paths, with_no_trimmed_paths};
814
use rustc_middle::ty::{
9-
GenericPredicates, Instance, ParamEnv, ScalarInt, TypeVisitableExt, ValTree,
15+
GenericPredicates, Instance, List, ParamEnv, ScalarInt, TyCtxt, TypeVisitableExt, ValTree,
1016
};
1117
use rustc_span::def_id::LOCAL_CRATE;
18+
use stable_mir::abi::{FnAbi, Layout, LayoutShape};
1219
use stable_mir::compiler_interface::Context;
1320
use stable_mir::mir::alloc::GlobalAlloc;
1421
use stable_mir::mir::mono::{InstanceDef, StaticDef};
@@ -280,7 +287,6 @@ impl<'tcx> Context for TablesWrapper<'tcx> {
280287
tables.tcx.mk_ty_from_kind(internal_kind).stable(&mut *tables)
281288
}
282289

283-
#[allow(rustc::usage_of_qualified_ty)]
284290
fn new_box_ty(&self, ty: stable_mir::ty::Ty) -> stable_mir::ty::Ty {
285291
let mut tables = self.0.borrow_mut();
286292
let inner = ty.internal(&mut *tables);
@@ -335,6 +341,12 @@ impl<'tcx> Context for TablesWrapper<'tcx> {
335341
instance.ty(tables.tcx, ParamEnv::reveal_all()).stable(&mut *tables)
336342
}
337343

344+
fn instance_abi(&self, def: InstanceDef) -> Result<FnAbi, Error> {
345+
let mut tables = self.0.borrow_mut();
346+
let instance = tables.instances[def];
347+
Ok(tables.fn_abi_of_instance(instance, List::empty())?.stable(&mut *tables))
348+
}
349+
338350
fn instance_def_id(&self, def: InstanceDef) -> stable_mir::DefId {
339351
let mut tables = self.0.borrow_mut();
340352
let def_id = tables.instances[def].def_id();
@@ -473,6 +485,65 @@ impl<'tcx> Context for TablesWrapper<'tcx> {
473485
)
474486
}
475487
}
488+
489+
fn ty_layout(&self, ty: Ty) -> Result<Layout, Error> {
490+
let mut tables = self.0.borrow_mut();
491+
let ty = ty.internal(&mut *tables);
492+
let layout = tables.layout_of(ty)?.layout;
493+
Ok(layout.stable(&mut *tables))
494+
}
495+
496+
fn layout_shape(&self, id: Layout) -> LayoutShape {
497+
let mut tables = self.0.borrow_mut();
498+
id.internal(&mut *tables).0.stable(&mut *tables)
499+
}
476500
}
477501

478502
pub struct TablesWrapper<'tcx>(pub RefCell<Tables<'tcx>>);
503+
504+
/// Implement error handling for extracting function ABI information.
505+
impl<'tcx> FnAbiOfHelpers<'tcx> for Tables<'tcx> {
506+
type FnAbiOfResult = Result<&'tcx rustc_target::abi::call::FnAbi<'tcx, ty::Ty<'tcx>>, Error>;
507+
508+
#[inline]
509+
fn handle_fn_abi_err(
510+
&self,
511+
err: ty::layout::FnAbiError<'tcx>,
512+
_span: rustc_span::Span,
513+
fn_abi_request: ty::layout::FnAbiRequest<'tcx>,
514+
) -> Error {
515+
Error::new(format!("Failed to get ABI for `{fn_abi_request:?}`: {err:?}"))
516+
}
517+
}
518+
519+
impl<'tcx> LayoutOfHelpers<'tcx> for Tables<'tcx> {
520+
type LayoutOfResult = Result<ty::layout::TyAndLayout<'tcx>, Error>;
521+
522+
#[inline]
523+
fn handle_layout_err(
524+
&self,
525+
err: ty::layout::LayoutError<'tcx>,
526+
_span: rustc_span::Span,
527+
ty: ty::Ty<'tcx>,
528+
) -> Error {
529+
Error::new(format!("Failed to get layout for `{ty}`: {err}"))
530+
}
531+
}
532+
533+
impl<'tcx> HasParamEnv<'tcx> for Tables<'tcx> {
534+
fn param_env(&self) -> ty::ParamEnv<'tcx> {
535+
ty::ParamEnv::reveal_all()
536+
}
537+
}
538+
539+
impl<'tcx> HasTyCtxt<'tcx> for Tables<'tcx> {
540+
fn tcx(&self) -> TyCtxt<'tcx> {
541+
self.tcx
542+
}
543+
}
544+
545+
impl<'tcx> HasDataLayout for Tables<'tcx> {
546+
fn data_layout(&self) -> &rustc_abi::TargetDataLayout {
547+
self.tcx.data_layout()
548+
}
549+
}
Lines changed: 242 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,242 @@
1+
//! Conversion of internal Rust compiler `rustc_target::abi` and `rustc_abi` items to stable ones.
2+
3+
#![allow(rustc::usage_of_qualified_ty)]
4+
5+
use crate::rustc_smir::{Stable, Tables};
6+
use rustc_middle::ty;
7+
use rustc_target::abi::call::Conv;
8+
use stable_mir::abi::{
9+
ArgAbi, CallConvention, FieldsShape, FnAbi, Layout, LayoutShape, PassMode, TagEncoding,
10+
TyAndLayout, ValueAbi, VariantsShape,
11+
};
12+
use stable_mir::ty::{Align, IndexedVal, Size, VariantIdx};
13+
use stable_mir::{opaque, Opaque};
14+
15+
impl<'tcx> Stable<'tcx> for rustc_target::abi::VariantIdx {
16+
type T = VariantIdx;
17+
fn stable(&self, _: &mut Tables<'tcx>) -> Self::T {
18+
VariantIdx::to_val(self.as_usize())
19+
}
20+
}
21+
22+
impl<'tcx> Stable<'tcx> for rustc_abi::Endian {
23+
type T = stable_mir::target::Endian;
24+
25+
fn stable(&self, _tables: &mut Tables<'tcx>) -> Self::T {
26+
match self {
27+
rustc_abi::Endian::Little => stable_mir::target::Endian::Little,
28+
rustc_abi::Endian::Big => stable_mir::target::Endian::Big,
29+
}
30+
}
31+
}
32+
33+
impl<'tcx> Stable<'tcx> for rustc_target::abi::TyAndLayout<'tcx, ty::Ty<'tcx>> {
34+
type T = TyAndLayout;
35+
36+
fn stable(&self, tables: &mut Tables<'tcx>) -> Self::T {
37+
TyAndLayout { ty: self.ty.stable(tables), layout: self.layout.stable(tables) }
38+
}
39+
}
40+
41+
impl<'tcx> Stable<'tcx> for rustc_target::abi::Layout<'tcx> {
42+
type T = Layout;
43+
44+
fn stable(&self, tables: &mut Tables<'tcx>) -> Self::T {
45+
tables.layout_id(*self)
46+
}
47+
}
48+
49+
impl<'tcx> Stable<'tcx>
50+
for rustc_abi::LayoutS<rustc_target::abi::FieldIdx, rustc_target::abi::VariantIdx>
51+
{
52+
type T = LayoutShape;
53+
54+
fn stable(&self, tables: &mut Tables<'tcx>) -> Self::T {
55+
LayoutShape {
56+
fields: self.fields.stable(tables),
57+
variants: self.variants.stable(tables),
58+
abi: self.abi.stable(tables),
59+
abi_align: self.align.abi.stable(tables),
60+
size: self.size.stable(tables),
61+
}
62+
}
63+
}
64+
65+
impl<'tcx> Stable<'tcx> for rustc_target::abi::call::FnAbi<'tcx, ty::Ty<'tcx>> {
66+
type T = FnAbi;
67+
68+
fn stable(&self, tables: &mut Tables<'tcx>) -> Self::T {
69+
assert!(self.args.len() >= self.fixed_count as usize);
70+
assert!(!self.c_variadic || matches!(self.conv, Conv::C));
71+
FnAbi {
72+
args: self.args.as_ref().stable(tables),
73+
ret: self.ret.stable(tables),
74+
fixed_count: self.fixed_count,
75+
conv: self.conv.stable(tables),
76+
c_variadic: self.c_variadic,
77+
}
78+
}
79+
}
80+
81+
impl<'tcx> Stable<'tcx> for rustc_target::abi::call::ArgAbi<'tcx, ty::Ty<'tcx>> {
82+
type T = ArgAbi;
83+
84+
fn stable(&self, tables: &mut Tables<'tcx>) -> Self::T {
85+
ArgAbi {
86+
ty: self.layout.ty.stable(tables),
87+
layout: self.layout.layout.stable(tables),
88+
mode: self.mode.stable(tables),
89+
}
90+
}
91+
}
92+
93+
impl<'tcx> Stable<'tcx> for rustc_target::abi::call::Conv {
94+
type T = CallConvention;
95+
96+
fn stable(&self, _tables: &mut Tables<'tcx>) -> Self::T {
97+
match self {
98+
Conv::C => CallConvention::C,
99+
Conv::Rust => CallConvention::Rust,
100+
Conv::Cold => CallConvention::Cold,
101+
Conv::PreserveMost => CallConvention::PreserveMost,
102+
Conv::PreserveAll => CallConvention::PreserveAll,
103+
Conv::ArmAapcs => CallConvention::ArmAapcs,
104+
Conv::CCmseNonSecureCall => CallConvention::CCmseNonSecureCall,
105+
Conv::Msp430Intr => CallConvention::Msp430Intr,
106+
Conv::PtxKernel => CallConvention::PtxKernel,
107+
Conv::X86Fastcall => CallConvention::X86Fastcall,
108+
Conv::X86Intr => CallConvention::X86Intr,
109+
Conv::X86Stdcall => CallConvention::X86Stdcall,
110+
Conv::X86ThisCall => CallConvention::X86ThisCall,
111+
Conv::X86VectorCall => CallConvention::X86VectorCall,
112+
Conv::X86_64SysV => CallConvention::X86_64SysV,
113+
Conv::X86_64Win64 => CallConvention::X86_64Win64,
114+
Conv::AmdGpuKernel => CallConvention::AmdGpuKernel,
115+
Conv::AvrInterrupt => CallConvention::AvrInterrupt,
116+
Conv::AvrNonBlockingInterrupt => CallConvention::AvrNonBlockingInterrupt,
117+
Conv::RiscvInterrupt { .. } => CallConvention::RiscvInterrupt,
118+
}
119+
}
120+
}
121+
122+
impl<'tcx> Stable<'tcx> for rustc_target::abi::call::PassMode {
123+
type T = PassMode;
124+
125+
fn stable(&self, _tables: &mut Tables<'tcx>) -> Self::T {
126+
match self {
127+
rustc_target::abi::call::PassMode::Ignore => PassMode::Ignore,
128+
rustc_target::abi::call::PassMode::Direct(attr) => PassMode::Direct(opaque(attr)),
129+
rustc_target::abi::call::PassMode::Pair(first, second) => {
130+
PassMode::Pair(opaque(first), opaque(second))
131+
}
132+
rustc_target::abi::call::PassMode::Cast { pad_i32, cast } => {
133+
PassMode::Cast { pad_i32: *pad_i32, cast: opaque(cast) }
134+
}
135+
rustc_target::abi::call::PassMode::Indirect { attrs, meta_attrs, on_stack } => {
136+
PassMode::Indirect {
137+
attrs: opaque(attrs),
138+
meta_attrs: opaque(meta_attrs),
139+
on_stack: *on_stack,
140+
}
141+
}
142+
}
143+
}
144+
}
145+
146+
impl<'tcx> Stable<'tcx> for rustc_abi::FieldsShape<rustc_target::abi::FieldIdx> {
147+
type T = FieldsShape;
148+
149+
fn stable(&self, tables: &mut Tables<'tcx>) -> Self::T {
150+
match self {
151+
rustc_abi::FieldsShape::Primitive => FieldsShape::Primitive,
152+
rustc_abi::FieldsShape::Union(count) => FieldsShape::Union(*count),
153+
rustc_abi::FieldsShape::Array { stride, count } => {
154+
FieldsShape::Array { stride: stride.stable(tables), count: *count }
155+
}
156+
rustc_abi::FieldsShape::Arbitrary { offsets, .. } => {
157+
FieldsShape::Arbitrary { offsets: offsets.iter().as_slice().stable(tables) }
158+
}
159+
}
160+
}
161+
}
162+
163+
impl<'tcx> Stable<'tcx>
164+
for rustc_abi::Variants<rustc_target::abi::FieldIdx, rustc_target::abi::VariantIdx>
165+
{
166+
type T = VariantsShape;
167+
168+
fn stable(&self, tables: &mut Tables<'tcx>) -> Self::T {
169+
match self {
170+
rustc_abi::Variants::Single { index } => {
171+
VariantsShape::Single { index: index.stable(tables) }
172+
}
173+
rustc_abi::Variants::Multiple { tag, tag_encoding, tag_field, variants } => {
174+
VariantsShape::Multiple {
175+
tag: tag.stable(tables),
176+
tag_encoding: tag_encoding.stable(tables),
177+
tag_field: *tag_field,
178+
variants: variants.iter().as_slice().stable(tables),
179+
}
180+
}
181+
}
182+
}
183+
}
184+
185+
impl<'tcx> Stable<'tcx> for rustc_abi::TagEncoding<rustc_target::abi::VariantIdx> {
186+
type T = TagEncoding;
187+
188+
fn stable(&self, tables: &mut Tables<'tcx>) -> Self::T {
189+
match self {
190+
rustc_abi::TagEncoding::Direct => TagEncoding::Direct,
191+
rustc_abi::TagEncoding::Niche { untagged_variant, niche_variants, niche_start } => {
192+
TagEncoding::Niche {
193+
untagged_variant: untagged_variant.stable(tables),
194+
niche_variants: niche_variants.stable(tables),
195+
niche_start: *niche_start,
196+
}
197+
}
198+
}
199+
}
200+
}
201+
202+
impl<'tcx> Stable<'tcx> for rustc_abi::Abi {
203+
type T = ValueAbi;
204+
205+
fn stable(&self, tables: &mut Tables<'tcx>) -> Self::T {
206+
match *self {
207+
rustc_abi::Abi::Uninhabited => ValueAbi::Uninhabited,
208+
rustc_abi::Abi::Scalar(scalar) => ValueAbi::Scalar(scalar.stable(tables)),
209+
rustc_abi::Abi::ScalarPair(first, second) => {
210+
ValueAbi::ScalarPair(first.stable(tables), second.stable(tables))
211+
}
212+
rustc_abi::Abi::Vector { element, count } => {
213+
ValueAbi::Vector { element: element.stable(tables), count }
214+
}
215+
rustc_abi::Abi::Aggregate { sized } => ValueAbi::Aggregate { sized },
216+
}
217+
}
218+
}
219+
220+
impl<'tcx> Stable<'tcx> for rustc_abi::Size {
221+
type T = Size;
222+
223+
fn stable(&self, _tables: &mut Tables<'tcx>) -> Self::T {
224+
self.bytes_usize()
225+
}
226+
}
227+
228+
impl<'tcx> Stable<'tcx> for rustc_abi::Align {
229+
type T = Align;
230+
231+
fn stable(&self, _tables: &mut Tables<'tcx>) -> Self::T {
232+
self.bytes()
233+
}
234+
}
235+
236+
impl<'tcx> Stable<'tcx> for rustc_abi::Scalar {
237+
type T = Opaque;
238+
239+
fn stable(&self, _tables: &mut Tables<'tcx>) -> Self::T {
240+
opaque(self)
241+
}
242+
}

‎compiler/rustc_smir/src/rustc_smir/convert/mod.rs

Lines changed: 1 addition & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,10 @@
11
//! Conversion of internal Rust compiler items to stable ones.
22
33
use rustc_target::abi::FieldIdx;
4-
use stable_mir::ty::{IndexedVal, VariantIdx};
54

65
use crate::rustc_smir::{Stable, Tables};
76

7+
mod abi;
88
mod error;
99
mod mir;
1010
mod ty;
@@ -26,13 +26,6 @@ impl<'tcx> Stable<'tcx> for FieldIdx {
2626
}
2727
}
2828

29-
impl<'tcx> Stable<'tcx> for rustc_target::abi::VariantIdx {
30-
type T = VariantIdx;
31-
fn stable(&self, _: &mut Tables<'tcx>) -> Self::T {
32-
VariantIdx::to_val(self.as_usize())
33-
}
34-
}
35-
3629
impl<'tcx> Stable<'tcx> for rustc_hir::CoroutineSource {
3730
type T = stable_mir::mir::CoroutineSource;
3831
fn stable(&self, _: &mut Tables<'tcx>) -> Self::T {
@@ -79,14 +72,3 @@ impl<'tcx> Stable<'tcx> for rustc_span::Span {
7972
tables.create_span(*self)
8073
}
8174
}
82-
83-
impl<'tcx> Stable<'tcx> for rustc_abi::Endian {
84-
type T = stable_mir::target::Endian;
85-
86-
fn stable(&self, _tables: &mut Tables<'tcx>) -> Self::T {
87-
match self {
88-
rustc_abi::Endian::Little => stable_mir::target::Endian::Little,
89-
rustc_abi::Endian::Big => stable_mir::target::Endian::Big,
90-
}
91-
}
92-
}

‎compiler/rustc_smir/src/rustc_smir/mod.rs

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,9 +12,11 @@ use rustc_middle::mir;
1212
use rustc_middle::mir::interpret::AllocId;
1313
use rustc_middle::ty::{self, Instance, Ty, TyCtxt};
1414
use rustc_span::def_id::{CrateNum, DefId, LOCAL_CRATE};
15+
use stable_mir::abi::Layout;
1516
use stable_mir::mir::mono::InstanceDef;
1617
use stable_mir::ty::{ConstId, Span};
1718
use stable_mir::ItemKind;
19+
use std::ops::RangeInclusive;
1820
use tracing::debug;
1921

2022
use crate::rustc_internal::IndexMap;
@@ -32,6 +34,7 @@ pub struct Tables<'tcx> {
3234
pub(crate) types: IndexMap<Ty<'tcx>, stable_mir::ty::Ty>,
3335
pub(crate) instances: IndexMap<ty::Instance<'tcx>, InstanceDef>,
3436
pub(crate) constants: IndexMap<mir::Const<'tcx>, ConstId>,
37+
pub(crate) layouts: IndexMap<rustc_target::abi::Layout<'tcx>, Layout>,
3538
}
3639

3740
impl<'tcx> Tables<'tcx> {
@@ -162,3 +165,13 @@ where
162165
(self.0.stable(tables), self.1.stable(tables))
163166
}
164167
}
168+
169+
impl<'tcx, T> Stable<'tcx> for RangeInclusive<T>
170+
where
171+
T: Stable<'tcx>,
172+
{
173+
type T = RangeInclusive<T::T>;
174+
fn stable(&self, tables: &mut Tables<'tcx>) -> Self::T {
175+
RangeInclusive::new(self.start().stable(tables), self.end().stable(tables))
176+
}
177+
}

‎compiler/stable_mir/src/abi.rs

Lines changed: 283 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,283 @@
1+
use crate::compiler_interface::with;
2+
use crate::mir::FieldIdx;
3+
use crate::ty::{Align, IndexedVal, Size, Ty, VariantIdx};
4+
use crate::Opaque;
5+
use std::num::NonZeroUsize;
6+
use std::ops::RangeInclusive;
7+
8+
/// A function ABI definition.
9+
#[derive(Clone, Debug, PartialEq, Eq, Hash)]
10+
pub struct FnAbi {
11+
/// The types of each argument.
12+
pub args: Vec<ArgAbi>,
13+
14+
/// The expected return type.
15+
pub ret: ArgAbi,
16+
17+
/// The count of non-variadic arguments.
18+
///
19+
/// Should only be different from `args.len()` when a function is a C variadic function.
20+
pub fixed_count: u32,
21+
22+
/// The ABI convention.
23+
pub conv: CallConvention,
24+
25+
/// Whether this is a variadic C function,
26+
pub c_variadic: bool,
27+
}
28+
29+
/// Information about the ABI of a function's argument, or return value.
30+
#[derive(Clone, Debug, PartialEq, Eq, Hash)]
31+
pub struct ArgAbi {
32+
pub ty: Ty,
33+
pub layout: Layout,
34+
pub mode: PassMode,
35+
}
36+
37+
/// How a function argument should be passed in to the target function.
38+
#[derive(Clone, Debug, PartialEq, Eq, Hash)]
39+
pub enum PassMode {
40+
/// Ignore the argument.
41+
///
42+
/// The argument is either uninhabited or a ZST.
43+
Ignore,
44+
/// Pass the argument directly.
45+
///
46+
/// The argument has a layout abi of `Scalar` or `Vector`.
47+
Direct(Opaque),
48+
/// Pass a pair's elements directly in two arguments.
49+
///
50+
/// The argument has a layout abi of `ScalarPair`.
51+
Pair(Opaque, Opaque),
52+
/// Pass the argument after casting it.
53+
Cast { pad_i32: bool, cast: Opaque },
54+
/// Pass the argument indirectly via a hidden pointer.
55+
Indirect { attrs: Opaque, meta_attrs: Opaque, on_stack: bool },
56+
}
57+
58+
/// The layout of a type, alongside the type itself.
59+
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
60+
pub struct TyAndLayout {
61+
pub ty: Ty,
62+
pub layout: Layout,
63+
}
64+
65+
/// The layout of a type in memory.
66+
#[derive(Clone, Debug, PartialEq, Eq, Hash)]
67+
pub struct LayoutShape {
68+
/// The fields location withing the layout
69+
pub fields: FieldsShape,
70+
71+
/// Encodes information about multi-variant layouts.
72+
/// Even with `Multiple` variants, a layout still has its own fields! Those are then
73+
/// shared between all variants.
74+
///
75+
/// To access all fields of this layout, both `fields` and the fields of the active variant
76+
/// must be taken into account.
77+
pub variants: VariantsShape,
78+
79+
/// The `abi` defines how this data is passed between functions.
80+
pub abi: ValueAbi,
81+
82+
/// The ABI mandated alignment in bytes.
83+
pub abi_align: Align,
84+
85+
/// The size of this layout in bytes.
86+
pub size: Size,
87+
}
88+
89+
impl LayoutShape {
90+
/// Returns `true` if the layout corresponds to an unsized type.
91+
#[inline]
92+
pub fn is_unsized(&self) -> bool {
93+
self.abi.is_unsized()
94+
}
95+
96+
#[inline]
97+
pub fn is_sized(&self) -> bool {
98+
!self.abi.is_unsized()
99+
}
100+
101+
/// Returns `true` if the type is sized and a 1-ZST (meaning it has size 0 and alignment 1).
102+
pub fn is_1zst(&self) -> bool {
103+
self.is_sized() && self.size == 0 && self.abi_align == 1
104+
}
105+
}
106+
107+
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
108+
pub struct Layout(usize);
109+
110+
impl Layout {
111+
pub fn shape(self) -> LayoutShape {
112+
with(|cx| cx.layout_shape(self))
113+
}
114+
}
115+
116+
impl IndexedVal for Layout {
117+
fn to_val(index: usize) -> Self {
118+
Layout(index)
119+
}
120+
fn to_index(&self) -> usize {
121+
self.0
122+
}
123+
}
124+
125+
/// Describes how the fields of a type are shaped in memory.
126+
#[derive(Clone, Debug, PartialEq, Eq, Hash)]
127+
pub enum FieldsShape {
128+
/// Scalar primitives and `!`, which never have fields.
129+
Primitive,
130+
131+
/// All fields start at no offset. The `usize` is the field count.
132+
Union(NonZeroUsize),
133+
134+
/// Array/vector-like placement, with all fields of identical types.
135+
Array { stride: Size, count: u64 },
136+
137+
/// Struct-like placement, with precomputed offsets.
138+
///
139+
/// Fields are guaranteed to not overlap, but note that gaps
140+
/// before, between and after all the fields are NOT always
141+
/// padding, and as such their contents may not be discarded.
142+
/// For example, enum variants leave a gap at the start,
143+
/// where the discriminant field in the enum layout goes.
144+
Arbitrary {
145+
/// Offsets for the first byte of each field,
146+
/// ordered to match the source definition order.
147+
/// I.e.: It follows the same order as [crate::ty::VariantDef::fields()].
148+
/// This vector does not go in increasing order.
149+
offsets: Vec<Size>,
150+
},
151+
}
152+
153+
impl FieldsShape {
154+
pub fn fields_by_offset_order(&self) -> Vec<FieldIdx> {
155+
match self {
156+
FieldsShape::Primitive => vec![],
157+
FieldsShape::Union(_) | FieldsShape::Array { .. } => (0..self.count()).collect(),
158+
FieldsShape::Arbitrary { offsets, .. } => {
159+
let mut indices = (0..offsets.len()).collect::<Vec<_>>();
160+
indices.sort_by_key(|idx| offsets[*idx]);
161+
indices
162+
}
163+
}
164+
}
165+
166+
pub fn count(&self) -> usize {
167+
match self {
168+
FieldsShape::Primitive => 0,
169+
FieldsShape::Union(count) => count.get(),
170+
FieldsShape::Array { count, .. } => *count as usize,
171+
FieldsShape::Arbitrary { offsets, .. } => offsets.len(),
172+
}
173+
}
174+
}
175+
176+
#[derive(Clone, Debug, PartialEq, Eq, Hash)]
177+
pub enum VariantsShape {
178+
/// Single enum variants, structs/tuples, unions, and all non-ADTs.
179+
Single { index: VariantIdx },
180+
181+
/// Enum-likes with more than one inhabited variant: each variant comes with
182+
/// a *discriminant* (usually the same as the variant index but the user can
183+
/// assign explicit discriminant values). That discriminant is encoded
184+
/// as a *tag* on the machine. The layout of each variant is
185+
/// a struct, and they all have space reserved for the tag.
186+
/// For enums, the tag is the sole field of the layout.
187+
Multiple {
188+
tag: Scalar,
189+
tag_encoding: TagEncoding,
190+
tag_field: usize,
191+
variants: Vec<LayoutShape>,
192+
},
193+
}
194+
195+
#[derive(Clone, Debug, PartialEq, Eq, Hash)]
196+
pub enum TagEncoding {
197+
/// The tag directly stores the discriminant, but possibly with a smaller layout
198+
/// (so converting the tag to the discriminant can require sign extension).
199+
Direct,
200+
201+
/// Niche (values invalid for a type) encoding the discriminant:
202+
/// Discriminant and variant index coincide.
203+
/// The variant `untagged_variant` contains a niche at an arbitrary
204+
/// offset (field `tag_field` of the enum), which for a variant with
205+
/// discriminant `d` is set to
206+
/// `(d - niche_variants.start).wrapping_add(niche_start)`.
207+
///
208+
/// For example, `Option<(usize, &T)>` is represented such that
209+
/// `None` has a null pointer for the second tuple field, and
210+
/// `Some` is the identity function (with a non-null reference).
211+
Niche {
212+
untagged_variant: VariantIdx,
213+
niche_variants: RangeInclusive<VariantIdx>,
214+
niche_start: u128,
215+
},
216+
}
217+
218+
/// Describes how values of the type are passed by target ABIs,
219+
/// in terms of categories of C types there are ABI rules for.
220+
#[derive(Clone, Debug, PartialEq, Eq, Hash)]
221+
pub enum ValueAbi {
222+
Uninhabited,
223+
Scalar(Scalar),
224+
ScalarPair(Scalar, Scalar),
225+
Vector {
226+
element: Scalar,
227+
count: u64,
228+
},
229+
Aggregate {
230+
/// If true, the size is exact, otherwise it's only a lower bound.
231+
sized: bool,
232+
},
233+
}
234+
235+
impl ValueAbi {
236+
/// Returns `true` if the layout corresponds to an unsized type.
237+
pub fn is_unsized(&self) -> bool {
238+
match *self {
239+
ValueAbi::Uninhabited
240+
| ValueAbi::Scalar(_)
241+
| ValueAbi::ScalarPair(..)
242+
| ValueAbi::Vector { .. } => false,
243+
ValueAbi::Aggregate { sized } => !sized,
244+
}
245+
}
246+
}
247+
248+
/// We currently do not support `Scalar`, and use opaque instead.
249+
type Scalar = Opaque;
250+
251+
/// General language calling conventions.
252+
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
253+
pub enum CallConvention {
254+
C,
255+
Rust,
256+
257+
Cold,
258+
PreserveMost,
259+
PreserveAll,
260+
261+
// Target-specific calling conventions.
262+
ArmAapcs,
263+
CCmseNonSecureCall,
264+
265+
Msp430Intr,
266+
267+
PtxKernel,
268+
269+
X86Fastcall,
270+
X86Intr,
271+
X86Stdcall,
272+
X86ThisCall,
273+
X86VectorCall,
274+
275+
X86_64SysV,
276+
X86_64Win64,
277+
278+
AmdGpuKernel,
279+
AvrInterrupt,
280+
AvrNonBlockingInterrupt,
281+
282+
RiscvInterrupt,
283+
}

‎compiler/stable_mir/src/compiler_interface.rs

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
66
use std::cell::Cell;
77

8+
use crate::abi::{FnAbi, Layout, LayoutShape};
89
use crate::mir::alloc::{AllocId, GlobalAlloc};
910
use crate::mir::mono::{Instance, InstanceDef, StaticDef};
1011
use crate::mir::Body;
@@ -173,6 +174,15 @@ pub trait Context {
173174

174175
/// Return information about the target machine.
175176
fn target_info(&self) -> MachineInfo;
177+
178+
/// Get an instance ABI.
179+
fn instance_abi(&self, def: InstanceDef) -> Result<FnAbi, Error>;
180+
181+
/// Get the layout of a type.
182+
fn ty_layout(&self, ty: Ty) -> Result<Layout, Error>;
183+
184+
/// Get the layout shape.
185+
fn layout_shape(&self, id: Layout) -> LayoutShape;
176186
}
177187

178188
// A thread local variable that stores a pointer to the tables mapping between TyCtxt

‎compiler/stable_mir/src/lib.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@ use crate::mir::Body;
3333
use crate::mir::Mutability;
3434
use crate::ty::{ImplDef, ImplTrait, IndexedVal, Span, TraitDecl, TraitDef, Ty};
3535

36+
pub mod abi;
3637
#[macro_use]
3738
pub mod crate_def;
3839
pub mod compiler_interface;

‎compiler/stable_mir/src/mir/mono.rs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
use crate::abi::FnAbi;
12
use crate::crate_def::CrateDef;
23
use crate::mir::Body;
34
use crate::ty::{Allocation, ClosureDef, ClosureKind, FnDef, GenericArgs, IndexedVal, Ty};
@@ -56,6 +57,11 @@ impl Instance {
5657
with(|context| context.instance_ty(self.def))
5758
}
5859

60+
/// Retrieve information about this instance binary interface.
61+
pub fn fn_abi(&self) -> Result<FnAbi, Error> {
62+
with(|cx| cx.instance_abi(self.def))
63+
}
64+
5965
/// Retrieve the instance's mangled name used for calling the given instance.
6066
///
6167
/// This will also look up the correct name of instances from upstream crates.

‎compiler/stable_mir/src/ty.rs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ use super::{
33
mir::{Body, Mutability},
44
with, DefId, Error, Symbol,
55
};
6+
use crate::abi::Layout;
67
use crate::crate_def::CrateDef;
78
use crate::mir::alloc::{read_target_int, read_target_uint, AllocId};
89
use crate::target::MachineInfo;
@@ -85,6 +86,11 @@ impl Ty {
8586
pub fn unsigned_ty(inner: UintTy) -> Ty {
8687
Ty::from_rigid_kind(RigidTy::Uint(inner))
8788
}
89+
90+
/// Get a type layout.
91+
pub fn layout(self) -> Result<Layout, Error> {
92+
with(|cx| cx.ty_layout(self))
93+
}
8894
}
8995

9096
impl Ty {
Lines changed: 143 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,143 @@
1+
// run-pass
2+
//! Test information regarding type layout.
3+
4+
// ignore-stage1
5+
// ignore-cross-compile
6+
// ignore-remote
7+
// ignore-windows-gnu mingw has troubles with linking https://github.com/rust-lang/rust/pull/116837
8+
9+
#![feature(rustc_private)]
10+
#![feature(assert_matches)]
11+
#![feature(control_flow_enum)]
12+
#![feature(ascii_char, ascii_char_variants)]
13+
14+
extern crate rustc_hir;
15+
extern crate rustc_middle;
16+
#[macro_use]
17+
extern crate rustc_smir;
18+
extern crate rustc_driver;
19+
extern crate rustc_interface;
20+
extern crate stable_mir;
21+
22+
use rustc_middle::ty::TyCtxt;
23+
use rustc_smir::rustc_internal;
24+
use stable_mir::abi::{ArgAbi, CallConvention, FieldsShape, PassMode, VariantsShape};
25+
use stable_mir::mir::mono::Instance;
26+
use stable_mir::{CrateDef, CrateItem, CrateItems, ItemKind};
27+
use std::assert_matches::assert_matches;
28+
use std::convert::TryFrom;
29+
use std::io::Write;
30+
use std::ops::ControlFlow;
31+
32+
const CRATE_NAME: &str = "input";
33+
34+
/// This function uses the Stable MIR APIs to get information about the test crate.
35+
fn test_stable_mir(_tcx: TyCtxt<'_>) -> ControlFlow<()> {
36+
// Find items in the local crate.
37+
let items = stable_mir::all_local_items();
38+
39+
// Test fn_abi
40+
let target_fn = *get_item(&items, (ItemKind::Fn, "fn_abi")).unwrap();
41+
let instance = Instance::try_from(target_fn).unwrap();
42+
let fn_abi = instance.fn_abi().unwrap();
43+
assert_eq!(fn_abi.conv, CallConvention::Rust);
44+
assert_eq!(fn_abi.args.len(), 2);
45+
46+
check_ignore(&fn_abi.args[0]);
47+
check_primitive(&fn_abi.args[1]);
48+
check_result(fn_abi.ret);
49+
50+
// Test variadic function.
51+
let variadic_fn = *get_item(&items, (ItemKind::Fn, "variadic_fn")).unwrap();
52+
check_variadic(variadic_fn);
53+
54+
ControlFlow::Continue(())
55+
}
56+
57+
/// Check the variadic function ABI:
58+
/// ```no_run
59+
/// pub unsafe extern "C" fn variadic_fn(n: usize, mut args: ...) -> usize {
60+
/// 0
61+
/// }
62+
/// ```
63+
fn check_variadic(variadic_fn: CrateItem) {
64+
let instance = Instance::try_from(variadic_fn).unwrap();
65+
let abi = instance.fn_abi().unwrap();
66+
assert!(abi.c_variadic);
67+
assert_eq!(abi.args.len(), 1);
68+
}
69+
70+
/// Check the argument to be ignored: `ignore: [u8; 0]`.
71+
fn check_ignore(abi: &ArgAbi) {
72+
assert!(abi.ty.kind().is_array());
73+
assert_eq!(abi.mode, PassMode::Ignore);
74+
let layout = abi.layout.shape();
75+
assert!(layout.is_sized());
76+
assert!(layout.is_1zst());
77+
}
78+
79+
/// Check the primitive argument: `primitive: char`.
80+
fn check_primitive(abi: &ArgAbi) {
81+
assert!(abi.ty.kind().is_char());
82+
assert_matches!(abi.mode, PassMode::Direct(_));
83+
let layout = abi.layout.shape();
84+
assert!(layout.is_sized());
85+
assert!(!layout.is_1zst());
86+
assert_matches!(layout.fields, FieldsShape::Primitive);
87+
}
88+
89+
/// Check the return value: `Result<usize, &str>`.
90+
fn check_result(abi: ArgAbi) {
91+
assert!(abi.ty.kind().is_enum());
92+
assert_matches!(abi.mode, PassMode::Indirect { .. });
93+
let layout = abi.layout.shape();
94+
assert!(layout.is_sized());
95+
assert_matches!(layout.fields, FieldsShape::Arbitrary { .. });
96+
assert_matches!(layout.variants, VariantsShape::Multiple { .. })
97+
}
98+
99+
fn get_item<'a>(
100+
items: &'a CrateItems,
101+
item: (ItemKind, &str),
102+
) -> Option<&'a stable_mir::CrateItem> {
103+
items.iter().find(|crate_item| (item.0 == crate_item.kind()) && crate_item.name() == item.1)
104+
}
105+
106+
/// This test will generate and analyze a dummy crate using the stable mir.
107+
/// For that, it will first write the dummy crate into a file.
108+
/// Then it will create a `StableMir` using custom arguments and then
109+
/// it will run the compiler.
110+
fn main() {
111+
let path = "alloc_input.rs";
112+
generate_input(&path).unwrap();
113+
let args = vec![
114+
"rustc".to_string(),
115+
"--crate-type=lib".to_string(),
116+
"--crate-name".to_string(),
117+
CRATE_NAME.to_string(),
118+
path.to_string(),
119+
];
120+
run!(args, tcx, test_stable_mir(tcx)).unwrap();
121+
}
122+
123+
fn generate_input(path: &str) -> std::io::Result<()> {
124+
let mut file = std::fs::File::create(path)?;
125+
write!(
126+
file,
127+
r#"
128+
#![feature(c_variadic)]
129+
#![allow(unused_variables)]
130+
131+
pub fn fn_abi(ignore: [u8; 0], primitive: char) -> Result<usize, &'static str> {{
132+
// We only care about the signature.
133+
todo!()
134+
}}
135+
136+
137+
pub unsafe extern "C" fn variadic_fn(n: usize, mut args: ...) -> usize {{
138+
0
139+
}}
140+
"#
141+
)?;
142+
Ok(())
143+
}

‎tests/ui-fulldeps/stable-mir/check_allocation.rs

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -209,7 +209,6 @@ fn check_len(item: CrateItem) {
209209
assert_eq!(alloc.read_uint(), Ok(2));
210210
}
211211

212-
// Use internal API to find a function in a crate.
213212
fn get_item<'a>(
214213
items: &'a CrateItems,
215214
item: (ItemKind, &str),

‎tests/ui-fulldeps/stable-mir/check_defs.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -69,9 +69,9 @@ fn extract_elem_ty(ty: Ty) -> Ty {
6969

7070
/// Check signature and type of `Vec::<u8>::new` and its generic version.
7171
fn test_vec_new(instance: mir::mono::Instance) {
72-
let sig = instance.ty().kind().fn_sig().unwrap().skip_binder();
73-
assert_matches!(sig.inputs(), &[]);
74-
let elem_ty = extract_elem_ty(sig.output());
72+
let sig = instance.fn_abi().unwrap();
73+
assert_eq!(&sig.args, &[]);
74+
let elem_ty = extract_elem_ty(sig.ret.ty);
7575
assert_matches!(elem_ty.kind(), TyKind::RigidTy(RigidTy::Uint(UintTy::U8)));
7676

7777
// Get the signature for Vec::<T>::new.

0 commit comments

Comments
 (0)
This repository has been archived.