-
Notifications
You must be signed in to change notification settings - Fork 13k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Move MIR towards a single kind of local #36752
Conversation
If MIR is for a "rust-call" ABI function, the last arg would always have `spread` set to `true`. Move this flag into `Mir` instead.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM modulo nits. cc @rust-lang/compiler In case anyone has anything to say against it.
/// is passed as its individual components at the LLVM level. | ||
/// | ||
/// This is used for the "rust-call" ABI. | ||
pub spread_last_arg: bool, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'd rather have an Option<Local>
here instead, special-casing the last argument is a step backwards for VG.
/// Returns an iterator over all function arguments. | ||
#[inline] | ||
pub fn arg_iter<'a>(&'a self) -> impl Iterator<Item=Local> + 'a { | ||
(1..self.arg_count+1).map(Local::new) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This doesn't need to borrow self
.
|
||
/// Returns an iterator over all temporaries. | ||
#[inline] | ||
pub fn temp_iter<'a>(&'a self) -> impl Iterator<Item=Local> + 'a { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The usual conversion would be temps
, I believe (same for the ones below).
} | ||
repr::Operand::Consume(_) | | ||
repr::Operand::Consume(ref lval) => match *lval { | ||
repr::Lvalue::Local(local) if mir.local_kind(local) == LocalKind::Temp => { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Don't think this code should care. cc @pnkfelix
Lvalue::Var(var) => Some(Local::new(var.index() + self.arg_count)), | ||
Lvalue::Temp(temp) => { | ||
Some(Local::new(temp.index() + self.arg_count + self.var_count)) | ||
if let Lvalue::Local(local) = *lvalue { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sweet! I'm sorry @pcwalton had to write this in the first place, but, this is all in hindsight.
block: BasicBlock::new(0), | ||
statement_index: usize::MAX | ||
}); | ||
self.assign(Lvalue::ReturnPointer, rvalue, span); | ||
|
||
self.assign(Lvalue::Local(RETURN_POINTER), rvalue, span); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Might be able to change assign
to take a Local
.
let retptr = allocate_local(mir::RETURN_POINTER); | ||
iter::once(retptr) | ||
.chain(args.into_iter()) | ||
.chain(mir.var_and_temp_iter().map(&mut allocate_local)) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why not move allocate_local
into the map
call?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This has gone through a refactoring, I'll remove the &mut
.
// return = Baz { x: tmp0, y: const F32(0), z: const false }; // scope ... | ||
// local2 = local1; // scope 0 at main.rs:8:8: 8:9 | ||
// local3 = local2; // scope 1 at main.rs:9:14: 9:15 | ||
// local0 = Baz { x: local3, y: const F32(0), z: const false }; // scope ... |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Losing the names is unfortunate, do you think we could recover them?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Do you mean what kind of local each one is? We could recover that, but the full MIR dump already contains variable names so you can differentiate temps and variables. The full dump also has a comment on local0
explaining that it's the return pointer.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It's harder to read though. Maybe if it was %5
like in LLVM or _5
, it'd be easier. But still.
I guess there's no easy way to recover that information due to how it's printed.
/// Returns an iterator over all user-defined variables and compiler-generated temporaries (all | ||
/// locals that are neither arguments nor the return pointer). | ||
#[inline] | ||
pub fn vars_and_temps_iter<'a>(&'a self) -> impl Iterator<Item=Local> + 'a { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This also doesn't need 'a
.
// they are the two sub-fields of a single aggregate field. | ||
let meta = &fcx.fn_ty.args[idx]; | ||
if let Some(spread_local) = mir.spread_arg { | ||
if local == spread_local { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You can write this as if Some(local) == mir.spread_arg
.
LGTM, but the loss of names in the MIR is somewhat annoying. If we can't easily recover the original names, then since all locals are now printed the same, I'd prefer to make the prefix short, like @eddyb's |
We could recover the local kind (by threading a For the record, here's a "full" MIR dump for a small test program after this patch:
fn testroutine(start: u8, end: u8) -> u8 {
(start..end+1).map(|i| i * i).sum()
} |
We could possibly annotate each |
There's no need for a long prefix, since there's nothing to distinguish anymore.
They're ignored by the test runner, so let's not suggest that they matter
@bors r+ |
📌 Commit d2c8893 has been approved by |
Move MIR towards a single kind of local This PR modifies MIR to handle function arguments (`Arg`), user-defined variable bindings (`Var`), compiler-generated temporaries (`Tmp`), as well as the return value pointer equally. All of them are replaced with a single `Local` type, a few functions for iterating over different kinds of locals, and a way to get the kind of local we're dealing with (mainly used in the constant qualification/propagation passes). ~~I haven't managed to fix one remaining issue: A `StorageDead` not getting emitted for a variable (see the `TODO` in the test). If that's fixed, this is basically good to go.~~ Found the issue (an off-by-one error), fix incoming. r? @eddyb for changes to constant qualification and propagation I'm not quite sure about
This PR modifies MIR to handle function arguments (
Arg
), user-defined variable bindings (Var
), compiler-generated temporaries (Tmp
), as well as the return value pointer equally. All of them are replaced with a singleLocal
type, a few functions for iterating over different kinds of locals, and a way to get the kind of local we're dealing with (mainly used in the constant qualification/propagation passes).I haven't managed to fix one remaining issue: AFound the issue (an off-by-one error), fix incoming.StorageDead
not getting emitted for a variable (see theTODO
in the test). If that's fixed, this is basically good to go.r? @eddyb for changes to constant qualification and propagation I'm not quite sure about