Skip to content

Commit 1a83c5b

Browse files
committedDec 18, 2023
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.
1 parent 2a76340 commit 1a83c5b

File tree

14 files changed

+760
-25
lines changed

14 files changed

+760
-25
lines changed
 

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

+9
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

+6
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

+73-2
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+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,229 @@
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+
FnAbi {
70+
args: self.args.as_ref().stable(tables),
71+
ret: self.ret.stable(tables),
72+
fixed_count: self.fixed_count,
73+
conv: self.conv.stable(tables),
74+
}
75+
}
76+
}
77+
78+
impl<'tcx> Stable<'tcx> for rustc_target::abi::call::ArgAbi<'tcx, ty::Ty<'tcx>> {
79+
type T = ArgAbi;
80+
81+
fn stable(&self, tables: &mut Tables<'tcx>) -> Self::T {
82+
ArgAbi {
83+
ty: self.layout.ty.stable(tables),
84+
layout: self.layout.layout.stable(tables),
85+
mode: self.mode.stable(tables),
86+
}
87+
}
88+
}
89+
90+
impl<'tcx> Stable<'tcx> for rustc_target::abi::call::Conv {
91+
type T = CallConvention;
92+
93+
fn stable(&self, _tables: &mut Tables<'tcx>) -> Self::T {
94+
match self {
95+
Conv::C => CallConvention::C,
96+
Conv::Rust => CallConvention::Rust,
97+
Conv::Cold => CallConvention::Cold,
98+
Conv::PreserveMost => CallConvention::PreserveMost,
99+
Conv::PreserveAll => CallConvention::PreserveAll,
100+
Conv::ArmAapcs => CallConvention::ArmAapcs,
101+
Conv::CCmseNonSecureCall => CallConvention::CCmseNonSecureCall,
102+
Conv::Msp430Intr => CallConvention::Msp430Intr,
103+
Conv::PtxKernel => CallConvention::PtxKernel,
104+
Conv::X86Fastcall => CallConvention::X86Fastcall,
105+
Conv::X86Intr => CallConvention::X86Intr,
106+
Conv::X86Stdcall => CallConvention::X86Stdcall,
107+
Conv::X86ThisCall => CallConvention::X86ThisCall,
108+
Conv::X86VectorCall => CallConvention::X86VectorCall,
109+
Conv::X86_64SysV => CallConvention::X86_64SysV,
110+
Conv::X86_64Win64 => CallConvention::X86_64Win64,
111+
Conv::AmdGpuKernel => CallConvention::AmdGpuKernel,
112+
Conv::AvrInterrupt => CallConvention::AvrInterrupt,
113+
Conv::AvrNonBlockingInterrupt => CallConvention::AvrNonBlockingInterrupt,
114+
Conv::RiscvInterrupt { .. } => CallConvention::RiscvInterrupt,
115+
}
116+
}
117+
}
118+
119+
impl<'tcx> Stable<'tcx> for rustc_target::abi::call::PassMode {
120+
type T = PassMode;
121+
122+
fn stable(&self, _tables: &mut Tables<'tcx>) -> Self::T {
123+
match self {
124+
rustc_target::abi::call::PassMode::Ignore => PassMode::Ignore,
125+
rustc_target::abi::call::PassMode::Direct(_) => PassMode::Direct,
126+
rustc_target::abi::call::PassMode::Pair(_, _) => PassMode::Pair,
127+
rustc_target::abi::call::PassMode::Cast { .. } => PassMode::Cast,
128+
rustc_target::abi::call::PassMode::Indirect { .. } => PassMode::Indirect,
129+
}
130+
}
131+
}
132+
133+
impl<'tcx> Stable<'tcx> for rustc_abi::FieldsShape<rustc_target::abi::FieldIdx> {
134+
type T = FieldsShape;
135+
136+
fn stable(&self, tables: &mut Tables<'tcx>) -> Self::T {
137+
match self {
138+
rustc_abi::FieldsShape::Primitive => FieldsShape::Primitive,
139+
rustc_abi::FieldsShape::Union(count) => FieldsShape::Union(*count),
140+
rustc_abi::FieldsShape::Array { stride, count } => {
141+
FieldsShape::Array { stride: stride.stable(tables), count: *count }
142+
}
143+
rustc_abi::FieldsShape::Arbitrary { offsets, .. } => {
144+
FieldsShape::Arbitrary { offsets: offsets.iter().as_slice().stable(tables) }
145+
}
146+
}
147+
}
148+
}
149+
150+
impl<'tcx> Stable<'tcx>
151+
for rustc_abi::Variants<rustc_target::abi::FieldIdx, rustc_target::abi::VariantIdx>
152+
{
153+
type T = VariantsShape;
154+
155+
fn stable(&self, tables: &mut Tables<'tcx>) -> Self::T {
156+
match self {
157+
rustc_abi::Variants::Single { index } => {
158+
VariantsShape::Single { index: index.stable(tables) }
159+
}
160+
rustc_abi::Variants::Multiple { tag, tag_encoding, tag_field, variants } => {
161+
VariantsShape::Multiple {
162+
tag: tag.stable(tables),
163+
tag_encoding: tag_encoding.stable(tables),
164+
tag_field: *tag_field,
165+
variants: variants.iter().as_slice().stable(tables),
166+
}
167+
}
168+
}
169+
}
170+
}
171+
172+
impl<'tcx> Stable<'tcx> for rustc_abi::TagEncoding<rustc_target::abi::VariantIdx> {
173+
type T = TagEncoding;
174+
175+
fn stable(&self, tables: &mut Tables<'tcx>) -> Self::T {
176+
match self {
177+
rustc_abi::TagEncoding::Direct => TagEncoding::Direct,
178+
rustc_abi::TagEncoding::Niche { untagged_variant, niche_variants, niche_start } => {
179+
TagEncoding::Niche {
180+
untagged_variant: untagged_variant.stable(tables),
181+
niche_variants: niche_variants.stable(tables),
182+
niche_start: *niche_start,
183+
}
184+
}
185+
}
186+
}
187+
}
188+
189+
impl<'tcx> Stable<'tcx> for rustc_abi::Abi {
190+
type T = ValueAbi;
191+
192+
fn stable(&self, tables: &mut Tables<'tcx>) -> Self::T {
193+
match *self {
194+
rustc_abi::Abi::Uninhabited => ValueAbi::Uninhabited,
195+
rustc_abi::Abi::Scalar(scalar) => ValueAbi::Scalar(scalar.stable(tables)),
196+
rustc_abi::Abi::ScalarPair(first, second) => {
197+
ValueAbi::ScalarPair(first.stable(tables), second.stable(tables))
198+
}
199+
rustc_abi::Abi::Vector { element, count } => {
200+
ValueAbi::Vector { element: element.stable(tables), count }
201+
}
202+
rustc_abi::Abi::Aggregate { sized } => ValueAbi::Aggregate { sized },
203+
}
204+
}
205+
}
206+
207+
impl<'tcx> Stable<'tcx> for rustc_abi::Size {
208+
type T = Size;
209+
210+
fn stable(&self, _tables: &mut Tables<'tcx>) -> Self::T {
211+
self.bytes_usize()
212+
}
213+
}
214+
215+
impl<'tcx> Stable<'tcx> for rustc_abi::Align {
216+
type T = Align;
217+
218+
fn stable(&self, _tables: &mut Tables<'tcx>) -> Self::T {
219+
self.bytes()
220+
}
221+
}
222+
223+
impl<'tcx> Stable<'tcx> for rustc_abi::Scalar {
224+
type T = Opaque;
225+
226+
fn stable(&self, _tables: &mut Tables<'tcx>) -> Self::T {
227+
opaque(self)
228+
}
229+
}

0 commit comments

Comments
 (0)