-
Notifications
You must be signed in to change notification settings - Fork 13.2k
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
Lower to a memset(undef) when Rvalue::Repeat repeats uninit #138634
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -86,13 +86,30 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { | |
} | ||
|
||
mir::Rvalue::Repeat(ref elem, count) => { | ||
let cg_elem = self.codegen_operand(bx, elem); | ||
|
||
// Do not generate the loop for zero-sized elements or empty arrays. | ||
if dest.layout.is_zst() { | ||
return; | ||
} | ||
|
||
// When the element is a const with all bytes uninit, emit a single memset that | ||
// writes undef to the entire destination. | ||
if let mir::Operand::Constant(const_op) = elem { | ||
let val = self.eval_mir_constant(const_op); | ||
if val.all_bytes_uninit(self.cx.tcx()) { | ||
let size = bx.const_usize(dest.layout.size.bytes()); | ||
bx.memset( | ||
dest.val.llval, | ||
bx.const_undef(bx.type_i8()), | ||
size, | ||
dest.val.align, | ||
MemFlags::empty(), | ||
); | ||
Comment on lines
+100
to
+106
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Hmm, llvm accepts storing undef even for things like array types https://llvm.godbolt.org/z/jYjaEYsTh -- even though using those types like that is wrong in most places -- so I don't actually know what's better here. Eh, leave it as this is probably fine, since it's to There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I figured we can |
||
return; | ||
} | ||
} | ||
|
||
let cg_elem = self.codegen_operand(bx, elem); | ||
|
||
let try_init_all_same = |bx: &mut Bx, v| { | ||
let start = dest.val.llval; | ||
let size = bx.const_usize(dest.layout.size.bytes()); | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,21 @@ | ||
//@ compile-flags: -Copt-level=3 | ||
|
||
#![crate_type = "lib"] | ||
|
||
use std::mem::MaybeUninit; | ||
|
||
// We need to make sure len is at offset 0, otherwise codegen needs an extra instruction | ||
#[repr(C)] | ||
pub struct SmallVec<T> { | ||
pub len: u64, | ||
pub arr: [MaybeUninit<T>; 24], | ||
} | ||
|
||
// CHECK-LABEL: @uninit_arr_via_const | ||
#[no_mangle] | ||
pub fn uninit_arr_via_const() -> SmallVec<String> { | ||
// CHECK-NEXT: start: | ||
// CHECK-NEXT: store i64 0, | ||
// CHECK-NEXT: ret | ||
SmallVec { len: 0, arr: [const { MaybeUninit::uninit() }; 24] } | ||
} |
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.
pondering: with this change we'll skip evaluating the operand to repeat if the target is zero-sized.
I think that's ok, though? If it's a
Move
orCopy
at worst it's notmove
ing the thing, but moving from something doesn't actually do anything right now anyway. And if it's aConstant
something else is supposed to have evaluated it before we get here, right? So we don't need to worry about[const { panic!() }; 10]
somehow getting skipped for a ZST element type?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.
Yes, the whole mentioned items system is designed to guarantee that this isn't a problem:
rust/compiler/rustc_monomorphize/src/collector.rs
Lines 159 to 162 in 48b36c9