Skip to content

Commit 0522649

Browse files
authored
Unrolled build for rust-lang#117095
Rollup merge of rust-lang#117095 - klinvill:smir-fn-arg-count, r=oli-obk Add way to differentiate argument locals from other locals in Stable MIR This PR resolves rust-lang/project-stable-mir#47 which request a way to differentiate argument locals in a SMIR `Body` from other locals. Specifically, this PR exposes the `arg_count` field from the MIR `Body`. However, I'm opening this as a draft PR because I think there are a few outstanding questions on how this information should be exposed and described. Namely: - Is exposing `arg_count` the best way to surface this information to SMIR users? Would it be better to leave `arg_count` as a private field and add public methods (e.g. `fn arguments(&self) -> Iter<'_, LocalDecls>`) that may use the underlying `arg_count` info from the MIR body, but expose this information to users in a more convenient form? Or is it best to stick close to the current MIR convention? - If the answer to the above point is to stick with the current MIR convention (`arg_count`), is it reasonable to also commit to sticking to the current MIR convention that the first local is always the return local, while the next `arg_count` locals are always the (in-order) argument locals? - Should `Body` in SMIR only represent function bodies (as implied by the comment I added)? That seems to be the current case in MIR, but should this restriction always be the case for SMIR? r? `@celinval` r? `@oli-obk`
2 parents 698db85 + d55487d commit 0522649

File tree

5 files changed

+102
-22
lines changed

5 files changed

+102
-22
lines changed

compiler/rustc_smir/src/rustc_smir/mod.rs

+5-6
Original file line numberDiff line numberDiff line change
@@ -287,9 +287,8 @@ impl<'tcx> Stable<'tcx> for mir::Body<'tcx> {
287287
type T = stable_mir::mir::Body;
288288

289289
fn stable(&self, tables: &mut Tables<'tcx>) -> Self::T {
290-
stable_mir::mir::Body {
291-
blocks: self
292-
.basic_blocks
290+
stable_mir::mir::Body::new(
291+
self.basic_blocks
293292
.iter()
294293
.map(|block| stable_mir::mir::BasicBlock {
295294
terminator: block.terminator().stable(tables),
@@ -300,15 +299,15 @@ impl<'tcx> Stable<'tcx> for mir::Body<'tcx> {
300299
.collect(),
301300
})
302301
.collect(),
303-
locals: self
304-
.local_decls
302+
self.local_decls
305303
.iter()
306304
.map(|decl| stable_mir::mir::LocalDecl {
307305
ty: decl.ty.stable(tables),
308306
span: decl.source_info.span.stable(tables),
309307
})
310308
.collect(),
311-
}
309+
self.arg_count,
310+
)
312311
}
313312
}
314313

compiler/stable_mir/src/mir/body.rs

+53-3
Original file line numberDiff line numberDiff line change
@@ -2,10 +2,60 @@ use crate::ty::{AdtDef, ClosureDef, Const, CoroutineDef, GenericArgs, Movability
22
use crate::Opaque;
33
use crate::{ty::Ty, Span};
44

5+
/// The SMIR representation of a single function.
56
#[derive(Clone, Debug)]
67
pub struct Body {
78
pub blocks: Vec<BasicBlock>,
8-
pub locals: LocalDecls,
9+
10+
// Declarations of locals within the function.
11+
//
12+
// The first local is the return value pointer, followed by `arg_count`
13+
// locals for the function arguments, followed by any user-declared
14+
// variables and temporaries.
15+
locals: LocalDecls,
16+
17+
// The number of arguments this function takes.
18+
arg_count: usize,
19+
}
20+
21+
impl Body {
22+
/// Constructs a `Body`.
23+
///
24+
/// A constructor is required to build a `Body` from outside the crate
25+
/// because the `arg_count` and `locals` fields are private.
26+
pub fn new(blocks: Vec<BasicBlock>, locals: LocalDecls, arg_count: usize) -> Self {
27+
// If locals doesn't contain enough entries, it can lead to panics in
28+
// `ret_local`, `arg_locals`, and `inner_locals`.
29+
assert!(
30+
locals.len() > arg_count,
31+
"A Body must contain at least a local for the return value and each of the function's arguments"
32+
);
33+
Self { blocks, locals, arg_count }
34+
}
35+
36+
/// Return local that holds this function's return value.
37+
pub fn ret_local(&self) -> &LocalDecl {
38+
&self.locals[0]
39+
}
40+
41+
/// Locals in `self` that correspond to this function's arguments.
42+
pub fn arg_locals(&self) -> &[LocalDecl] {
43+
&self.locals[1..][..self.arg_count]
44+
}
45+
46+
/// Inner locals for this function. These are the locals that are
47+
/// neither the return local nor the argument locals.
48+
pub fn inner_locals(&self) -> &[LocalDecl] {
49+
&self.locals[self.arg_count + 1..]
50+
}
51+
52+
/// Convenience function to get all the locals in this function.
53+
///
54+
/// Locals are typically accessed via the more specific methods `ret_local`,
55+
/// `arg_locals`, and `inner_locals`.
56+
pub fn locals(&self) -> &[LocalDecl] {
57+
&self.locals
58+
}
959
}
1060

1161
type LocalDecls = Vec<LocalDecl>;
@@ -467,7 +517,7 @@ pub enum NullOp {
467517
}
468518

469519
impl Operand {
470-
pub fn ty(&self, locals: &LocalDecls) -> Ty {
520+
pub fn ty(&self, locals: &[LocalDecl]) -> Ty {
471521
match self {
472522
Operand::Copy(place) | Operand::Move(place) => place.ty(locals),
473523
Operand::Constant(c) => c.ty(),
@@ -482,7 +532,7 @@ impl Constant {
482532
}
483533

484534
impl Place {
485-
pub fn ty(&self, locals: &LocalDecls) -> Ty {
535+
pub fn ty(&self, locals: &[LocalDecl]) -> Ty {
486536
let _start_ty = locals[self.local].ty;
487537
todo!("Implement projection")
488538
}

tests/ui-fulldeps/stable-mir/check_instance.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -59,7 +59,7 @@ fn test_body(body: mir::Body) {
5959
for term in body.blocks.iter().map(|bb| &bb.terminator) {
6060
match &term.kind {
6161
Call { func, .. } => {
62-
let TyKind::RigidTy(ty) = func.ty(&body.locals).kind() else { unreachable!() };
62+
let TyKind::RigidTy(ty) = func.ty(body.locals()).kind() else { unreachable!() };
6363
let RigidTy::FnDef(def, args) = ty else { unreachable!() };
6464
let result = Instance::resolve(def, &args);
6565
assert!(result.is_ok());

tests/ui-fulldeps/stable-mir/crate-info.rs

+42-11
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,7 @@ fn test_stable_mir(_tcx: TyCtxt<'_>) -> ControlFlow<()> {
4747

4848
let bar = get_item(&items, (DefKind::Fn, "bar")).unwrap();
4949
let body = bar.body();
50-
assert_eq!(body.locals.len(), 2);
50+
assert_eq!(body.locals().len(), 2);
5151
assert_eq!(body.blocks.len(), 1);
5252
let block = &body.blocks[0];
5353
assert_eq!(block.statements.len(), 1);
@@ -62,7 +62,7 @@ fn test_stable_mir(_tcx: TyCtxt<'_>) -> ControlFlow<()> {
6262

6363
let foo_bar = get_item(&items, (DefKind::Fn, "foo_bar")).unwrap();
6464
let body = foo_bar.body();
65-
assert_eq!(body.locals.len(), 5);
65+
assert_eq!(body.locals().len(), 5);
6666
assert_eq!(body.blocks.len(), 4);
6767
let block = &body.blocks[0];
6868
match &block.terminator.kind {
@@ -72,29 +72,29 @@ fn test_stable_mir(_tcx: TyCtxt<'_>) -> ControlFlow<()> {
7272

7373
let types = get_item(&items, (DefKind::Fn, "types")).unwrap();
7474
let body = types.body();
75-
assert_eq!(body.locals.len(), 6);
75+
assert_eq!(body.locals().len(), 6);
7676
assert_matches!(
77-
body.locals[0].ty.kind(),
77+
body.locals()[0].ty.kind(),
7878
stable_mir::ty::TyKind::RigidTy(stable_mir::ty::RigidTy::Bool)
7979
);
8080
assert_matches!(
81-
body.locals[1].ty.kind(),
81+
body.locals()[1].ty.kind(),
8282
stable_mir::ty::TyKind::RigidTy(stable_mir::ty::RigidTy::Bool)
8383
);
8484
assert_matches!(
85-
body.locals[2].ty.kind(),
85+
body.locals()[2].ty.kind(),
8686
stable_mir::ty::TyKind::RigidTy(stable_mir::ty::RigidTy::Char)
8787
);
8888
assert_matches!(
89-
body.locals[3].ty.kind(),
89+
body.locals()[3].ty.kind(),
9090
stable_mir::ty::TyKind::RigidTy(stable_mir::ty::RigidTy::Int(stable_mir::ty::IntTy::I32))
9191
);
9292
assert_matches!(
93-
body.locals[4].ty.kind(),
93+
body.locals()[4].ty.kind(),
9494
stable_mir::ty::TyKind::RigidTy(stable_mir::ty::RigidTy::Uint(stable_mir::ty::UintTy::U64))
9595
);
9696
assert_matches!(
97-
body.locals[5].ty.kind(),
97+
body.locals()[5].ty.kind(),
9898
stable_mir::ty::TyKind::RigidTy(stable_mir::ty::RigidTy::Float(
9999
stable_mir::ty::FloatTy::F64
100100
))
@@ -123,10 +123,10 @@ fn test_stable_mir(_tcx: TyCtxt<'_>) -> ControlFlow<()> {
123123
for block in instance.body().blocks {
124124
match &block.terminator.kind {
125125
stable_mir::mir::TerminatorKind::Call { func, .. } => {
126-
let TyKind::RigidTy(ty) = func.ty(&body.locals).kind() else { unreachable!() };
126+
let TyKind::RigidTy(ty) = func.ty(&body.locals()).kind() else { unreachable!() };
127127
let RigidTy::FnDef(def, args) = ty else { unreachable!() };
128128
let next_func = Instance::resolve(def, &args).unwrap();
129-
match next_func.body().locals[1].ty.kind() {
129+
match next_func.body().locals()[1].ty.kind() {
130130
TyKind::RigidTy(RigidTy::Uint(_)) | TyKind::RigidTy(RigidTy::Tuple(_)) => {}
131131
other => panic!("{other:?}"),
132132
}
@@ -140,6 +140,29 @@ fn test_stable_mir(_tcx: TyCtxt<'_>) -> ControlFlow<()> {
140140
// Ensure we don't panic trying to get the body of a constant.
141141
foo_const.body();
142142

143+
let locals_fn = get_item(&items, (DefKind::Fn, "locals")).unwrap();
144+
let body = locals_fn.body();
145+
assert_eq!(body.locals().len(), 4);
146+
assert_matches!(
147+
body.ret_local().ty.kind(),
148+
stable_mir::ty::TyKind::RigidTy(stable_mir::ty::RigidTy::Char)
149+
);
150+
assert_eq!(body.arg_locals().len(), 2);
151+
assert_matches!(
152+
body.arg_locals()[0].ty.kind(),
153+
stable_mir::ty::TyKind::RigidTy(stable_mir::ty::RigidTy::Int(stable_mir::ty::IntTy::I32))
154+
);
155+
assert_matches!(
156+
body.arg_locals()[1].ty.kind(),
157+
stable_mir::ty::TyKind::RigidTy(stable_mir::ty::RigidTy::Uint(stable_mir::ty::UintTy::U64))
158+
);
159+
assert_eq!(body.inner_locals().len(), 1);
160+
// If conditions have an extra inner local to hold their results
161+
assert_matches!(
162+
body.inner_locals()[0].ty.kind(),
163+
stable_mir::ty::TyKind::RigidTy(stable_mir::ty::RigidTy::Bool)
164+
);
165+
143166
ControlFlow::Continue(())
144167
}
145168

@@ -211,6 +234,14 @@ fn generate_input(path: &str) -> std::io::Result<()> {
211234
212235
pub fn assert(x: i32) -> i32 {{
213236
x + 1
237+
}}
238+
239+
pub fn locals(a: i32, _: u64) -> char {{
240+
if a > 5 {{
241+
'a'
242+
}} else {{
243+
'b'
244+
}}
214245
}}"#
215246
)?;
216247
Ok(())

tests/ui-fulldeps/stable-mir/smir_internal.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ const CRATE_NAME: &str = "input";
2929
fn test_translation(_tcx: TyCtxt<'_>) -> ControlFlow<()> {
3030
let main_fn = stable_mir::entry_fn().unwrap();
3131
let body = main_fn.body();
32-
let orig_ty = body.locals[0].ty;
32+
let orig_ty = body.locals()[0].ty;
3333
let rustc_ty = rustc_internal::internal(&orig_ty);
3434
assert!(rustc_ty.is_unit());
3535
ControlFlow::Continue(())

0 commit comments

Comments
 (0)