-
Notifications
You must be signed in to change notification settings - Fork 12.9k
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
Translate array drop glue using MIR #41917
Conversation
Can you check the optimized IR? Ideally we'd even have a test - I believe LLVM will turn it into a pointer loop. |
src/librustc/ty/util.rs
Outdated
@@ -578,6 +578,15 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { | |||
bug!("empty_substs_for_def_id: {:?} has type parameters", item_def_id) | |||
}) | |||
} | |||
|
|||
pub fn const_usize(&self, val: usize) -> ConstInt { |
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.
Shouldn't this usize
be a u64
to be correct when compiling from 32 bit to 64?
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.
In practice val
is either 0 or 1.
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 see, it's probably ok then (still, it'd be nice to prevent misuses of this function)
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.
u16
is probably a good option for the type then, so one can never pass a value too large.
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.
A few nits. I only skimmed translator changes, nothing obviously wrong there.
is_cleanup, | ||
terminator: Some(Terminator { | ||
source_info: self.source_info, | ||
kind: TerminatorKind::Resume, |
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.
NIT: Unreachable
here would make it much more obvious this terminator is patched out a bit later.
/// can_go = index < len | ||
/// if can_go then drop-block else succ | ||
/// drop-block: | ||
/// ptr = &mut LV[len] |
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.
NIT: s/len/index/
?
|
||
let is_cleanup = self.is_cleanup; | ||
let succ = self.succ; // FIXME(#6393) | ||
let loop_block = self.drop_loop(unwind, succ, index, length, ety, is_cleanup); |
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.
Is it guaranteed that is_cleanup
is always false
here? IIRC all the details related to this, it is guaranteed, in which this is_cleanup
flag is redundant (unwind
being None
or Some
already carries that information).
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.
is_cleanup
is technically always false here because this can't be reached from "normal" drop elaboration, but if we fixed drop glue for arrays it would be true.
@@ -691,4 +808,12 @@ impl<'l, 'b, 'tcx, D> DropCtxt<'l, 'b, 'tcx, D> | |||
let mir = self.elaborator.mir(); | |||
self.elaborator.patch().terminator_loc(mir, bb) | |||
} | |||
|
|||
fn constant_usize(&self, val: usize) -> Operand<'tcx> { |
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.
Ditto here wrt usize
/u16
.
|
||
let is_cleanup = self.is_cleanup; | ||
let succ = self.succ; // FIXME(#6393) | ||
let loop_block = self.drop_loop(unwind, succ, index, length, ety, is_cleanup); |
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'm worried about this code repeating itself for all used array lengths - would it be possible to have the array drop coerce to a *[T]
and drop that? Or is thst premature optimization?
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 code in question is fairly compact. I feel like LLVM would inline it in all cases anyway. The only really troublesome case I can imagine is somebody having a very large number of small arrays on stack.
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 was more worried about us instantiating so many copies of pretty much identical IR. But thinking more about it, various lengths of fixed-length arrays are somewhat rare in practice, so this might not be a problem at all.
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 expect LLVM to always inline this anyway. Note that this is translated inline today.
Nope it doesn't. I'll try to write up pointer loops tomorrow. |
@@ -323,7 +316,8 @@ impl<'l, 'b, 'tcx, D> DropCtxt<'l, 'b, 'tcx, D> | |||
self.elaborator.field_subpath(self.path, Field::new(i))) | |||
}).collect(); | |||
|
|||
self.drop_ladder(fields).0 | |||
let (succ, unwind) = (self.succ, self.unwind); // FIXME(#6393) |
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 issue noted in the FIXME (#6393) is closed... should it be changed to a different issue? This is also the case in a few other places in the code.
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 still easily track where to look from the comments in the issue (i.e. the niko’s in favour comment).
EDIT: nice trick. Amusing.
There’s some travis failures due to MIR variants being boxed now, @arielb1. You might want to rebase. |
succ = self.drop_subpath(lv, path, succ, unwind_succ); | ||
succ | ||
}).collect() | ||
Some(succ).into_iter().chain( |
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.
nit: iter::once(succ)
is a more compact way to express this.
The last commit looks good. |
42e03a2
to
1d9c6d2
Compare
@arielb1 is this waiting on review now? I couldn't immediately tell from the state of the PR. Just curious for what tags too apply! |
I'm trying to see whether I can get pointer-based iteration to work out nicely enough I'll want to use it. |
I feel like code could be a bit more clear if the index-based loop and the pointer-based loop were separate, rather than so closely intermingled in the same function. It is also not entirely clear to me that both These are the nits, feel free to ignore them. Now… I think it could be possible to avoid indexing the array altogether in the loop. That is, instead of generating:
It could be simplified(?) to this instead:
note the lack of actual “indexing” in the zero-sized case, which could plausibly make it easier for LLVM to optimise/unroll/etc the loop. I was actually going to propose just using It would also be worthwhile to have a FIXME somewhere to make SizeOf const-evaluated when possible, so SimplifyCfg could easily get rid of the other loop. |
Can you do an |
c8478fc
to
e99766b
Compare
this should fix the segfault |
src/librustc_trans/mir/block.rs
Outdated
|
||
// Create the cleanup bundle, if needed. | ||
let tcx = bcx.tcx(); | ||
let span = terminator.source_info.span; | ||
let funclet_bb = match self.cleanup_kinds[bb] { |
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 added a method (funclet_bb
) to CleanupKind
that does this, shouldn't we just call it here? Unless I'm missing some detail.
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.
umm yeah. fixed
LGTM. I asked on IRC:
but got no response. Feel free to r- if you feel like one is still necessary. @bors r+ |
📌 Commit 9bfe40e has been approved by |
⌛ Testing commit 9bfe40e with merge 8889b73... |
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.
Two minor nits. Looks great otherwise. r=me.
I won’t be able to look at github for a few upcoming days and won’t be able to instruct bors either.
src/librustc_trans/mir/mod.rs
Outdated
block_bcxs.iter_enumerated().zip(cleanup_kinds).map(|((bb, &llbb), cleanup_kind)| { | ||
match *cleanup_kind { | ||
CleanupKind::Funclet if base::wants_msvc_seh(ccx.sess()) => { | ||
let bcx = Builder::with_ccx(ccx); |
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 could create this builder outside the loop, avoiding an allocation and deallocation for each iteration, I think?
src/librustc_trans/mir/block.rs
Outdated
} | ||
CleanupKind::Internal { .. } => bcx.br(lltarget), | ||
CleanupKind::NotCleanup => bug!("jump from cleanup bb to bb {:?}", bb) | ||
let llblock2 = |this: &mut Self, target: mir::BasicBlock| { |
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 could use a better name. Something like cleanup_adjusted_llblock
maybe? lltarget_inner
or lltarget_common
could also work.
This fixes leakage on panic with arrays & slices. I am using a C-style for-loop instead of a pointer-based loop because that would be ugly-er to implement.
I'm not sure how well this works, but it's worth a try.
@bors r=nagisa |
📌 Commit 94f65c5 has been approved by |
@bors r=nagisa |
📌 Commit 137e710 has been approved by |
@bors r=nagisa |
📌 Commit ee982d4 has been approved by |
☀️ Test successful - status-appveyor, status-travis |
I was a bit lazy here and used a usize-based index instead of a pointer iteration. Do you think this is important @eddyb?
r? @eddyb