Stream: t-compiler/wg-mir-opt

Topic: Deref is not a projection


oli (Sep 30 2019 at 19:01, on Zulip):

btw, if there's anything const-eval or mir-opt related that needs more manpower I would be happy to help.

@ecstatic-morse This could conflict with @Santiago Pastorino but I think not too much (I'll let them be the judge of it). Removing Deref from the list of ProjectionElems is something that was discussed at the all hands this year. I'm not sure how easy it is. @RalfJ mentioned stacked borrows may not be able to handle it. I believe the issue is that (*y).z; is not the same thing as (&*y).z (because the former never touched stacked borrows because no (new!) references were involved). We can't just have an Rvalue::Reborrow and a Rvalue::Deref to differentiate, because (*large_type).x should not create a local to store large_type in just to read the x field a moment later. One proposition (I think, I may have projected a bit) was to have an Rvalue::DerefProject that first dereferences the PlaceBase before applying the projection. This scheme does not have the problem of large locals, as you only ever put pointers into locals

oli (Sep 30 2019 at 19:02, on Zulip):

cc @eddyb, too

ecstatic-morse (Sep 30 2019 at 19:04, on Zulip):

@oli Is there some place I can read up on the motivations for this change? Were there minutes for the all-hands discussion perhaps?

oli (Sep 30 2019 at 19:04, on Zulip):

yes, sec

oli (Sep 30 2019 at 19:04, on Zulip):

also motivation: Deref just makes all algorithms horrible

ecstatic-morse (Sep 30 2019 at 19:05, on Zulip):

^ I may have had some experience with this yes XD

Santiago Pastorino (Sep 30 2019 at 19:06, on Zulip):

btw, if there's anything const-eval or mir-opt related that needs more manpower I would be happy to help.

ecstatic-morse This could conflict with Santiago Pastorino but I think not too much (I'll let them be the judge of it). Removing Deref from the list of ProjectionElems is something that was discussed at the all hands this year. I'm not sure how easy it is. RalfJ mentioned stacked borrows may not be able to handle it. I believe the issue is that (*y).z; is not the same thing as (&*y).z (because the former never touched stacked borrows because no (new!) references were involved). We can't just have an Rvalue::Reborrow and a Rvalue::Deref to differentiate, because (*large_type).x should not create a local to store large_type in just to read the x field a moment later. One proposition (I think, I may have projected a bit) was to have an Rvalue::DerefProject that first dereferences the PlaceBase before applying the projection. This scheme does not have the problem of large locals, as you only ever put pointers into locals

unsure how much would this conflict with Place 2.0 next steps but I'd say let's find out what that is :P

oli (Sep 30 2019 at 19:06, on Zulip):

https://paper.dropbox.com/doc/Topic-MIR-2.0-and-MIR-Optimizations--Ak6z9Grd9UDtDZpvxqGy1fydAg-BwHR7kOhxDwL6vuAUoSTQ

oli (Sep 30 2019 at 19:06, on Zulip):

search for "instead of embedding"

oli (Sep 30 2019 at 19:08, on Zulip):

also "legal in MIR right"

oli (Sep 30 2019 at 19:09, on Zulip):

the stacked borrows problem only occurs if we inject &*, but my reading of @eddyb 's comment and my own interpretation of a DerefProject Rvalue would avoid that

oli (Sep 30 2019 at 19:10, on Zulip):

I think the only problem is that reborrows aren't possible anymore LOL oops

ecstatic-morse (Sep 30 2019 at 19:10, on Zulip):

I'll probably have to read Ralf's blog posts on stacked borrows to better understand the concerns around reborrowing

oli (Sep 30 2019 at 19:10, on Zulip):

I'm hoping to just avoid them entirely

oli (Sep 30 2019 at 19:11, on Zulip):

"them" being "injecting new reborrows where they weren't before"

Santiago Pastorino (Sep 30 2019 at 19:13, on Zulip):

@oli can you explain what was the idea with Deref?

Santiago Pastorino (Sep 30 2019 at 19:13, on Zulip):

so remove it from Place's projection

Santiago Pastorino (Sep 30 2019 at 19:13, on Zulip):

but how do you represent a deref instead?

ecstatic-morse (Sep 30 2019 at 19:15, on Zulip):

Ah okay. Did anyone float an alternative to or concerns about Rvalue::DerefProject(Place<'tcx>)? It seems like it solves all the problems here.

oli (Sep 30 2019 at 19:15, on Zulip):

so right now if you have (*a.b).c you have a, [b, deref, c] as the place, after this change we'd have let tmp = a.b; (*tmp).c

oli (Sep 30 2019 at 19:16, on Zulip):

Ah okay. Did anyone float an alternative to or concerns about Rvalue::DerefProject(Place<'tcx>)? It seems like it solves all the problems here.

I think other topics were more important and we were kinda going off on the wrong train of thought because noone grokked the stacked borrows problem fast enough to figure out that it's not a problem

oli (Sep 30 2019 at 19:19, on Zulip):

Since let tmp = a.b; (*tmp).c translates the latter expression to DerefProject(Place { base: tmp, projection: [c] }) but requires the base to always be dereferenced before use, we don't need any deref projections anymore

oli (Sep 30 2019 at 19:19, on Zulip):

some of the codegen code was in fact doing this. Injecting a local for the pointer

oli (Sep 30 2019 at 19:19, on Zulip):

or at least an llvm immediate

oli (Sep 30 2019 at 19:20, on Zulip):

well ok that was required anyway

oli (Sep 30 2019 at 19:20, on Zulip):

but I mean, there was extra code making sure the deref works out

oli (Sep 30 2019 at 19:20, on Zulip):

so if we have a mir local or magic codegen code makes no difference except that the former makes for much cleaner code

oli (Sep 30 2019 at 19:21, on Zulip):

@Santiago Pastorino remember the "iterate forward then backward" stuff when you made places be slices instead of recursive? That's what's going away if we do this

ecstatic-morse (Sep 30 2019 at 19:24, on Zulip):

@oli Wouldn't a reborrow be expressed as Rvalue::DerefProject(Place { base: tmp, projection: [borrow, ..] }). Like I said, I don't fully understand the semantics around reborrowing so maybe I'm too focused on this.

oli (Sep 30 2019 at 19:24, on Zulip):

@ecstatic-morse there's no borrow projection ;)

oli (Sep 30 2019 at 19:25, on Zulip):

we have Rvalue::Ref

ecstatic-morse (Sep 30 2019 at 19:25, on Zulip):

ohhhhh
duh

ecstatic-morse (Sep 30 2019 at 19:25, on Zulip):

Now I get it.

oli (Sep 30 2019 at 19:25, on Zulip):

place projections are supposed to just be fancy ways to write byte offsets

Wesley Wiser (Sep 30 2019 at 19:25, on Zulip):

Removing deref from projections seems like a really nice simplification to me. :thumbs_up:

I'm a little concerned you're going to run into issues with generators like I did a few weeks ago. There's code now that does _1 = (*_2).foo where _2 is a generator. At some point, I needed to get the layout of the place base (the generator) which triggers a query cycle. It's ok right now because most places just need to know the layout of the destination and bypass the intermediate deref but that may no longer be the case after we do this change.

Wesley Wiser (Sep 30 2019 at 19:25, on Zulip):

But we really need to solve that issue anyway...

oli (Sep 30 2019 at 19:26, on Zulip):

I think the generator thing would still work, as we'd just do Rvalue::DerefProject(Place { base: _2, projection: [foo] }) and not change anything else compared to right now

oli (Sep 30 2019 at 19:27, on Zulip):

but yes, that cycle sucks. Do we have an open issue for it? I remember posting a possible solution a la your mir/promoted split

Wesley Wiser (Sep 30 2019 at 19:27, on Zulip):

No, I'm not aware of an open issue.

Wesley Wiser (Sep 30 2019 at 19:27, on Zulip):

Let me find that idea though...

oli (Sep 30 2019 at 19:28, on Zulip):

ah thanks :heart: I gotta run in 3 minutes

ecstatic-morse (Sep 30 2019 at 19:28, on Zulip):

I mean we could have an Rvalue::ReborrowProject to do (&*x) and (&*x).foo, but I still don't fully understand the problem I'm trying to solve XD.

Wesley Wiser (Sep 30 2019 at 19:28, on Zulip):

(Context is here https://rust-lang.zulipchat.com/#narrow/stream/189540-t-compiler.2Fwg-mir-opt/topic/Using.20.60InterpCx.60.20more/near/175509886)

oli (Sep 30 2019 at 19:34, on Zulip):

I mean we could have an Rvalue::ReborrowProject to do (&*x) and (&*x).foo, but I still don't fully understand the problem I'm trying to solve XD.

yea, I mean ideally we'd not do any semantic changes in a PR that adds DerefProject and ReborrowProject (the latter is Rvalue::Ref btw) and then think about possible changes later

Santiago Pastorino (Sep 30 2019 at 21:33, on Zulip):

@oli sorry, I was away from Zulip, yeah makes a lot of sense, it was that I wasn't sure what was the plan :)

ecstatic-morse (Oct 01 2019 at 03:50, on Zulip):

I mean we could have an Rvalue::ReborrowProject to do (&*x) and (&*x).foo, but I still don't fully understand the problem I'm trying to solve XD.

yea, I mean ideally we'd not do any semantic changes in a PR that adds DerefProject and ReborrowProject (the latter is Rvalue::Ref btw) and then think about possible changes later

So currently when we do a reborrow (_2 = (&*_1)), we have an rvalue like Rvalue::Ref(Place { projections: [.., Deref] }). This lets passes that need to handle reborrows specifically do so by matching on the Rvalue. Const qualification makes use of this, for example, to ensure that _2 = (&*_1) behaves the same as _2 = _1 w.r.t. qualification. I don't think we want to encode reborrows as an Rvalue::DerefProject followed by an Rvalue::Ref, since then those passes that try to handle reborrows will need to look at multiple statements. That's why I proposed a separate Rvalue::ReborrowProject, so we would have an Rvalue variant for each of *x, &x and (&*x).

ecstatic-morse (Oct 01 2019 at 04:48, on Zulip):

Also, feel free to ping me if I don't reply in a timely fashion, I'm bad at checking zulip, and I've yet to find a way to filter notifications by topic

oli (Oct 01 2019 at 06:43, on Zulip):

@ecstatic-morse yea, you're right. I realized the same thing an hour after going offline :D

ecstatic-morse (Oct 03 2019 at 18:17, on Zulip):

I'm putting together a design doc for this so people can comment asynchronously. Perhaps someone will foresee an issue with the Deref/Reborrow strategy. Also, I want to call these DerefBase and ReborrowBase. I think this is clearer than using Project as a suffix. The design doc will include a strategy for splitting this into many small PRs that can be assigned, worked on and reviewed concurrently, since this will touch a lot of code.

nikomatsakis (Oct 04 2019 at 12:34, on Zulip):

@ecstatic-morse nice!

ecstatic-morse (Oct 04 2019 at 19:39, on Zulip):

One issue is that all other Rvalues also operate on Places, either directly or via Operand.Is it more efficient for some Rvalues to operate on a deref projection directly than if the pointee was copied to a local variable and the passed to the Rvalue?

ecstatic-morse (Oct 04 2019 at 19:39, on Zulip):

@oli ^

ecstatic-morse (Oct 04 2019 at 20:56, on Zulip):

Okay, I wrote up a proposal with a few of the design constraints. Please edit if you can think of more.

ecstatic-morse (Oct 04 2019 at 21:00, on Zulip):

It's also a bit light on motivation besides simplifying passes that need to check for Deref.

ecstatic-morse (Oct 04 2019 at 21:17, on Zulip):

The original MIR optimization doc alludes to some benefits in codegen. Perhaps someone who better understands this could comment?

nikomatsakis (Oct 07 2019 at 14:32, on Zulip):

one challenge is figuring out how to integrate this work with the borrow checker -- currently we benefit quite a bit from the fact that the "places" that the borrow checker wants to consider are "mostly" 1-to-1 with MIR places

nikomatsakis (Oct 07 2019 at 14:33, on Zulip):

I had vaguely assumed that we would approach this by having some kind of specially known operations for creating places, with a (by construction, probably) guarantee that the intermediate values are not used elsewhere

nikomatsakis (Oct 07 2019 at 14:35, on Zulip):

sorry, that's not very specific, there are a lot of moving parts to such an idea, since it interacts also with e.g. miri

nikomatsakis (Oct 07 2019 at 14:35, on Zulip):

but basically the idea was that where today we have a complex notion of Place like *(a.b.c[3]).d or whatever

nikomatsakis (Oct 07 2019 at 14:35, on Zulip):

we might instead break that down into smaller operations:

nikomatsakis (Oct 07 2019 at 14:36, on Zulip):
Place1 := a
Place2 := Place1.b
Place3 := Place2.c
Place4 := Place3[3]
Place5 := *Place4
Place6 := Place5.d
FinalReference = &Place6
nikomatsakis (Oct 07 2019 at 14:37, on Zulip):

where a "place value" is not a real value -- at least not to the borrow checker -- it must be linear (always consumed exactly once) and it must be "converted" to a real value, e.g. by a & operation

nikomatsakis (Oct 07 2019 at 14:37, on Zulip):

borrows might be somewhat special here; I guess all other uses of places are in operands that either copy or move? (well, assignments are also like borrows)

ecstatic-morse (Oct 07 2019 at 17:29, on Zulip):

Interesting, I would have expected that removing Deref from the list of MIR Place projections would make them even more similar to the "places" that the borrow checker wants to consider. Admittedly I don't know the borrow checker very well, so perhaps I'm wrong about this. How does the borrow checker track borrows of a deref currently?

ecstatic-morse (Oct 07 2019 at 17:33, on Zulip):

Regarding the virtual place idea, it seems to me like a different mental model around the existing Place representation. Once again, I don't know a lot about the existing borrow checker; things might be more clear if I did. Currently a "place value" is a Place, the smaller operations are projections, and the place is "converted" to a real value when it is passed to an Rvalue (Rvalue::Ref in your example).

nikomatsakis (Oct 07 2019 at 19:34, on Zulip):

Interesting, I would have expected that removing Deref from the list of MIR Place projections would make them even more similar to the "places" that the borrow checker wants to consider. Admittedly I don't know the borrow checker very well, so perhaps I'm wrong about this. How does the borrow checker track borrows of a deref currently?

specifically the case the borrow checker tracks is derefs of Box<T>

nikomatsakis (Oct 07 2019 at 19:35, on Zulip):

an alternative to all of this would be to leave Place during borrow check, but potentially "lower" to some other representation before optimizing (basically splitting up places that involve derefs)

ecstatic-morse (Oct 07 2019 at 20:15, on Zulip):

One thing to mention is that, if there's not any additional efficiencies in codegen, this change won't have any performance benefits that couldn't be gained from caching Place::is_indirect. If it makes the borrow checker analysis more convoluted, it's probably not worth doing.

ecstatic-morse (Oct 07 2019 at 20:16, on Zulip):

an alternative to all of this would be to leave Place during borrow check, but potentially "lower" to some other representation before optimizing (basically splitting up places that involve derefs)

This is intriguing. It seems like we could capture any efficiency gains in codegen with a much smaller set of changes.

ecstatic-morse (Oct 07 2019 at 20:17, on Zulip):

This is contingent on the existence of potential gains in codegen :smile:, which I'm assuming exist thanks to an offhand comment in meeting notes.

oli (Oct 08 2019 at 09:48, on Zulip):

I thought the MIR borrowchecker has quite a bunch of workarounds around Deref projections, too

nikomatsakis (Oct 08 2019 at 14:26, on Zulip):

We do have to reason about them

nikomatsakis (Oct 08 2019 at 14:26, on Zulip):

But I wouldn't call them workarounds

nikomatsakis (Oct 08 2019 at 14:26, on Zulip):

It's true that when you have (e.g.) derefs of &mut etc we have some special logic for borrowing such a thing

nikomatsakis (Oct 08 2019 at 14:27, on Zulip):

but I don't know that any of this logic would go away

nikomatsakis (Oct 08 2019 at 14:27, on Zulip):

and for sure we can't just remove them without something that takes their place that is not a move

oli (Oct 08 2019 at 14:27, on Zulip):

I meant that there's additional logic to unwind derefs in the middle of projection lists

nikomatsakis (Oct 08 2019 at 14:27, on Zulip):

I'm not sure what "unwind" means here

nikomatsakis (Oct 08 2019 at 14:28, on Zulip):

there is some special logic to account particularly for cases like

let mut p = &mut list;
loop {
    p = &mut p.next;
}
nikomatsakis (Oct 08 2019 at 14:28, on Zulip):

maybe that's what you're referring to?

nikomatsakis (Oct 08 2019 at 14:28, on Zulip):

at the same time, we have to also permit things like let x = &mut self.foo; let y = &mut self.bar;

oli (Oct 08 2019 at 14:28, on Zulip):

well, you may have [a, b, c, deref, d, e, f], and the compiler has a bunch of logic that fiddles up to the deref, does an operation, then does deref operations, then continues until the next deref

nikomatsakis (Oct 08 2019 at 14:28, on Zulip):

which means that we have one borrow of (*self).foo

nikomatsakis (Oct 08 2019 at 14:29, on Zulip):

and one borrow of (*self).bar

nikomatsakis (Oct 08 2019 at 14:29, on Zulip):

and we have to know that they are disjoint

nikomatsakis (Oct 08 2019 at 14:29, on Zulip):

that only makes sense if you consider the whole path

nikomatsakis (Oct 08 2019 at 14:29, on Zulip):

well, you may have [a, b, c, deref, d, e, f], and the compiler has a bunch of logic that fiddles up to the deref, does an operation, then does deref operations, then continues until the next deref

not really

nikomatsakis (Oct 08 2019 at 14:29, on Zulip):

at least I'm not sure what that is

nikomatsakis (Oct 08 2019 at 14:29, on Zulip):

maybe I'm forgetting things :)

nikomatsakis (Oct 08 2019 at 14:29, on Zulip):

at the same time, we have to also permit things like let x = &mut self.foo; let y = &mut self.bar;

this is the high order bit though, we have to reason about this "borrowed path"

oli (Oct 08 2019 at 14:30, on Zulip):

codegen has it definitely, and I thought I saw the same pattern in borrowck when reviewing @Santiago Pastorino 's PRs

nikomatsakis (Oct 08 2019 at 14:30, on Zulip):

there are definitely some cases where deref is "different" -- which are there to handle the loop case

oli (Oct 08 2019 at 14:30, on Zulip):

these two examples don't have any Deref projection

nikomatsakis (Oct 08 2019 at 14:30, on Zulip):

but I don't think it really "unwinds" quite in the way you suggest

nikomatsakis (Oct 08 2019 at 14:30, on Zulip):

these two examples don't have any Deref projection

yes they do

nikomatsakis (Oct 08 2019 at 14:30, on Zulip):

typically self: &mut Struct

nikomatsakis (Oct 08 2019 at 14:31, on Zulip):

so &mut self.bar => &mut (*self).bar

nikomatsakis (Oct 08 2019 at 14:31, on Zulip):

sorry, that was kind of hidden :)

oli (Oct 08 2019 at 14:31, on Zulip):

ah right

nikomatsakis (Oct 08 2019 at 14:31, on Zulip):

the key point being that if you did &mut *self as a separate step, you'd have two overlapping borrows

oli (Oct 08 2019 at 14:31, on Zulip):

so the suggestion in https://paper.dropbox.com/doc/aGnvFEPxejaDOXWDvfcf0 would still keep all possibilities for that around, but we'd need to track extra state possibly

nikomatsakis (Oct 08 2019 at 14:32, on Zulip):

this is why I was proposing that we might want to have some explicit "intermediate steps" that we know will always be intermedaites

oli (Oct 08 2019 at 14:32, on Zulip):

well it would be an entirely new Rvalue, thus borrowck could work with it

oli (Oct 08 2019 at 14:32, on Zulip):

but I see how that would complicate things

nikomatsakis (Oct 08 2019 at 14:33, on Zulip):

it might be ok if it's an rvalue, but I feel like it's different from an rvalue

oli (Oct 08 2019 at 14:34, on Zulip):

you mean the &mut *self shouldn't even be stored in a local but in one of these intermediate locals?

nikomatsakis (Oct 08 2019 at 14:34, on Zulip):

that's what I mean

nikomatsakis (Oct 08 2019 at 14:35, on Zulip):

but I also mean that &mut *self and *self are different

nikomatsakis (Oct 08 2019 at 14:35, on Zulip):

basically, there are two places where we use "places" to be "by-ref" -- i.e., to get at the memory they refer to and now the value in that memory

nikomatsakis (Oct 08 2019 at 14:35, on Zulip):

the lhs of an assignment, and a borrow

nikomatsakis (Oct 08 2019 at 14:36, on Zulip):

"rvalue" (to me) is meant to be something that creates a value -- in this case, I'm not 100% sure what the value is... a pointer I guess? it doesn't have a proper rust type

nikomatsakis (Oct 08 2019 at 14:36, on Zulip):

I guess it could be &mut T -- but the borrow that creates it is somehow different

oli (Oct 08 2019 at 14:37, on Zulip):

well... the *self part is an rvalue reference in c++, which is technically of type T

nikomatsakis (Oct 08 2019 at 14:38, on Zulip):

right, so this is the new thing :)

nikomatsakis (Oct 08 2019 at 14:38, on Zulip):

MIR doesn't have "references" right now

nikomatsakis (Oct 08 2019 at 14:38, on Zulip):

those are handled by places

nikomatsakis (Oct 08 2019 at 14:38, on Zulip):

but now we're kind of producing a new kind of value, which is a reference to a place

nikomatsakis (Oct 08 2019 at 14:38, on Zulip):

and I am sort of saying "maybe that's good, but we should put some strict limitations on how they are used"

nikomatsakis (Oct 08 2019 at 14:38, on Zulip):

i.e., they are intermediaries used to build up proper values, which are producing by "borrowing" them

oli (Oct 08 2019 at 14:39, on Zulip):

or consuming them

nikomatsakis (Oct 08 2019 at 14:39, on Zulip):

this would also integrate with miri, in that the borrow operation is the point where we "claim memory"

nikomatsakis (Oct 08 2019 at 14:39, on Zulip):

right, they can be

oli (Oct 08 2019 at 14:40, on Zulip):

Operand::Copy and Move would also be operating on these places

nikomatsakis (Oct 08 2019 at 14:40, on Zulip):

mm... yes, ok

nikomatsakis (Oct 08 2019 at 14:40, on Zulip):

so they can be

nikomatsakis (Oct 08 2019 at 14:40, on Zulip):
oli (Oct 08 2019 at 14:41, on Zulip):

so... this is all the places where Places are used right now?

nikomatsakis (Oct 08 2019 at 14:41, on Zulip):

of course :)

nikomatsakis (Oct 08 2019 at 14:41, on Zulip):

the new thing is the first bullet, I guess

nikomatsakis (Oct 08 2019 at 14:41, on Zulip):

i.e., the idea is that where we now have a complex, compound place

nikomatsakis (Oct 08 2019 at 14:41, on Zulip):

we'd only have some simpler form, and there'd be some way to do a "deref-projection"

nikomatsakis (Oct 08 2019 at 14:41, on Zulip):

in the limit, you could have all places just be variables

nikomatsakis (Oct 08 2019 at 14:42, on Zulip):

this is kind of the "per MIR place interning" I guess but baked in :P

nikomatsakis (Oct 08 2019 at 14:42, on Zulip):

(not quite, because projections would be copied everywhere)

nikomatsakis (Oct 08 2019 at 14:42, on Zulip):

in the limit, you could have all places just be variables

not variables really

nikomatsakis (Oct 08 2019 at 14:42, on Zulip):

place variables

oli (Oct 08 2019 at 14:42, on Zulip):

so we're flattening places to be just (PlaceBase, PlaceElem) instead of (PlaceBase, Box<[PlaceElem]>)

nikomatsakis (Oct 08 2019 at 14:42, on Zulip):

i.e., P2 = P1.f

nikomatsakis (Oct 08 2019 at 14:42, on Zulip):

well, I think what might be better would be to keep "GEP-like" projections

nikomatsakis (Oct 08 2019 at 14:42, on Zulip):

and so the only real new thing is P1 = *P2

oli (Oct 08 2019 at 14:43, on Zulip):

and runtime index ops

nikomatsakis (Oct 08 2019 at 14:43, on Zulip):

mm, yes,

nikomatsakis (Oct 08 2019 at 14:43, on Zulip):

and that

nikomatsakis (Oct 08 2019 at 14:43, on Zulip):

so you can "embed" foo.a.b as a place

nikomatsakis (Oct 08 2019 at 14:43, on Zulip):

I guess it means that PlaceBase now includes some kind of PlaceRef alternative, so it isn't always "rooted" in a local

nikomatsakis (Oct 08 2019 at 14:44, on Zulip):

and we have some kind of "single use" restriction on PlaceRefs

nikomatsakis (Oct 08 2019 at 14:44, on Zulip):

(stronger than SSA, in other words)

oli (Oct 08 2019 at 14:44, on Zulip):

yes

oli (Oct 08 2019 at 14:45, on Zulip):

and we also have a new Statement::Project or sth that takes a PlaceLocalId and a Place?

nikomatsakis (Oct 08 2019 at 14:46, on Zulip):

yeah

nikomatsakis (Oct 08 2019 at 14:46, on Zulip):

well wait

nikomatsakis (Oct 08 2019 at 14:46, on Zulip):

I am imagining something like ProjectDeref and ProjectIndex

oli (Oct 08 2019 at 14:46, on Zulip):

hmm... can we at that point just make the current Place be Box<[(Place, NonGEPProj)]>?

oli (Oct 08 2019 at 14:47, on Zulip):

well no

oli (Oct 08 2019 at 14:47, on Zulip):

uh

oli (Oct 08 2019 at 14:47, on Zulip):

let me untangle my thought

nikomatsakis (Oct 08 2019 at 14:47, on Zulip):

I am imagining

Place =
  X // local variable
| P // place variable
| Place `.` Field

Statement =
  Place = Rvalue
| P := * Place
| P := Place [ Place ]
| ...
nikomatsakis (Oct 08 2019 at 14:48, on Zulip):

sorry, I think easiest with grammars for some reason :)

nikomatsakis (Oct 08 2019 at 14:48, on Zulip):

those map to enums in a fairly straightforward way I guess

nikomatsakis (Oct 08 2019 at 14:48, on Zulip):

also, I probably excluded some "GEP-like" place options

nikomatsakis (Oct 08 2019 at 14:48, on Zulip):

oh, I think @eddyb wanted to make "pull out constants" as the base of a place, so we might also include P := Static or something

nikomatsakis (Oct 08 2019 at 14:49, on Zulip):

I'm using := as the "define a new place variable" notation

oli (Oct 08 2019 at 14:49, on Zulip):

since we have a "single use" rule, do we even need place variables? Can't we make places just be a (PlaceBase, [Proj]) for enum Proj { NonGepProj(NonGepProj), GepProj(Vec<PlaceElem>) } ?

nikomatsakis (Oct 08 2019 at 14:50, on Zulip):

isn't that what we have now :)

nikomatsakis (Oct 08 2019 at 14:50, on Zulip):

maybe I don't understand what NonGepProj is meant to be

oli (Oct 08 2019 at 14:50, on Zulip):

hm... yea sorry, ignore that

nikomatsakis (Oct 08 2019 at 14:51, on Zulip):

I think that "place variables" could be lowered to real values in a fairly easy way

nikomatsakis (Oct 08 2019 at 14:51, on Zulip):

basically they become pointers

nikomatsakis (Oct 08 2019 at 14:51, on Zulip):

which seems worth pointing out

nikomatsakis (Oct 08 2019 at 14:51, on Zulip):

(and maybe their Rust type is even *mut Foo or something)

oli (Oct 08 2019 at 14:51, on Zulip):

you want to be able to turn MIR with place variables to MIR without them?

nikomatsakis (Oct 08 2019 at 14:51, on Zulip):

presumably optimizations would start to handle them that way

nikomatsakis (Oct 08 2019 at 14:51, on Zulip):

right, you can just start treating them as pointers, right?

oli (Oct 08 2019 at 14:52, on Zulip):

after borrowck that should be possible

nikomatsakis (Oct 08 2019 at 14:52, on Zulip):

I think that is the point of all this, roughly speaking

nikomatsakis (Oct 08 2019 at 14:52, on Zulip):

that borrow-ck gets to view them as special

nikomatsakis (Oct 08 2019 at 14:52, on Zulip):

but afterwards we just kind of "forget" that

oli (Oct 08 2019 at 14:52, on Zulip):

iirc miri should just work if you turned a borrowchecked program into one using raw pointers everywhere

nikomatsakis (Oct 08 2019 at 14:52, on Zulip):

that said, if polonius is a success

nikomatsakis (Oct 08 2019 at 14:52, on Zulip):

well, nm

nikomatsakis (Oct 08 2019 at 14:53, on Zulip):

it's just that -- it's plausible borrowck could be integrated differently

nikomatsakis (Oct 08 2019 at 14:53, on Zulip):

as polonius creates a kind of "layer" between MIR and its input

nikomatsakis (Oct 08 2019 at 14:53, on Zulip):

(which is risky, since that was one of the things MIR was meant to fix :) but the layer is fairly simple, not complex like EUV)

nikomatsakis (Oct 08 2019 at 14:54, on Zulip):

I don't think that changes anything too fundamental though

nikomatsakis (Oct 08 2019 at 14:54, on Zulip):

the tl;dr is that we want some way to easily extract the path that was borrowed "in full"

nikomatsakis (Oct 08 2019 at 14:54, on Zulip):

while later kind of converting to a simpler IR with less complex structure

nikomatsakis (Oct 08 2019 at 14:55, on Zulip):

(maybe these "place references" are actually locals of type *mut T and a special flag, even?)

oli (Oct 08 2019 at 14:55, on Zulip):

right, similar to how we need the generator stuff up to a point and then just never use those statements again

oli (Oct 08 2019 at 14:55, on Zulip):

(maybe these "place references" are actually locals of type *mut T and a special flag, even?)

we could teach TyKind about them

nikomatsakis (Oct 08 2019 at 14:56, on Zulip):

true

nikomatsakis (Oct 08 2019 at 14:56, on Zulip):

(I guess that could serve as the flag)

oli (Oct 08 2019 at 14:57, on Zulip):

and would probably serve as a canary for accidentally using a local without checking the flag

RalfJ (Oct 09 2019 at 13:12, on Zulip):

yeah the & would have to be somehow special-magic for Stacked Borrows to make this work... but I expect the same special-magic will be needed to make the borrow checker work so that should be fine

RalfJ (Oct 09 2019 at 13:13, on Zulip):

also this is "funny" timing, one PhD student here is just right now working on extending our formal MIR-like model with support for * in paths...

RalfJ (Oct 09 2019 at 13:14, on Zulip):

but given that the borrow checker still has to support existing code, I'd actually be surprised if borrow checking would work on paths that don't have *. it seems more likely that the borrow checker will work on a notion of paths that's separate from what MIR does?

nikomatsakis (Oct 11 2019 at 20:39, on Zulip):

@RalfJ that's exactly it; MIR would have a more limited notion of paths, but borrow checker would be able to reconstruct its more extended notion in a simple way from the MIR

RalfJ (Oct 12 2019 at 13:59, on Zulip):

that'll be... interesting ;)

Last update: Nov 17 2019 at 07:25UTC